ExplicitExpansion () вызывает расширение OData не работает

Aug 20 2020

При использовании ExplicitExpansion () Odata expand не работает. Мои модели DTo и EF можно найти по ссылке ниже. Запросы DTO на основе EF с использованием Odata

Мой класс Automapper:

public class AutoMapperProfile : Profile
{
    public AutoMapperProfile()
    {
        CreateMap<ClientRef, ClientContract>().
        ForMember(dest => dest.ValidFrom,
        opt =>
        {
            opt.MapFrom(y => y.Clients.FirstOrDefault(x => x.ValidFrom <= DateTime.Now && x.ValidTo > DateTime.Now).ValidFrom);
        }).
        ForMember(dest => dest.ValidTo,
        opt =>
        {
            opt.MapFrom(y => y.Clients.FirstOrDefault(x => x.ValidFrom <= DateTime.Now && x.ValidTo > DateTime.Now).ValidTo);
        }).
       ForMember(dest => dest.FirstName,
        opt =>
        {
            opt.MapFrom(y => y.PhysicalPeople.FirstOrDefault(x => x.ValidFrom <= DateTime.Now && x.ValidTo > DateTime.Now).FirstName);
        }).
        ForMember(dest => dest.LastName,
        opt =>
        {
            opt.MapFrom(y => y.PhysicalPeople.FirstOrDefault(x => x.ValidFrom <= DateTime.Now && x.ValidTo > DateTime.Now).LastName);
        }).
        ForMember(dest => dest.BirthDate,
        opt =>
        {
            opt.MapFrom(y => y.PhysicalPeople.FirstOrDefault(x => x.ValidFrom <= DateTime.Now && x.ValidTo > DateTime.Now).BirthDate);
        }).
        ForMember(dest => dest.FatherName,
        opt =>
        {
            opt.MapFrom(y => y.PhysicalPeople.FirstOrDefault(x => x.ValidFrom <= DateTime.Now && x.ValidTo > DateTime.Now).FatherName);
        }).
        ForMember(dest => dest.CompanyName,
        opt =>
        {
            opt.MapFrom(y => y.Companies.FirstOrDefault(x => x.ValidFrom <= DateTime.Now && x.ValidTo > DateTime.Now).CompanyName);

        })
        .
        ForMember(dest => dest.PinNumber,
        opt =>
        {
            opt.MapFrom(y => y.PhysicalPeople.FirstOrDefault(x => x.ValidFrom <= DateTime.Now && x.ValidTo > DateTime.Now).Pin);

        }).
        ForMember(dest => dest.Position,
        opt =>
        {
            opt.MapFrom(y => y.PhysicalPeople.FirstOrDefault(x => x.ValidFrom <= DateTime.Now && x.ValidTo > DateTime.Now).Position);

        }).
        ForMember(dest => dest.PositionCustom,
        opt =>
        {
            opt.MapFrom(y => y.PhysicalPeople.FirstOrDefault(x => x.ValidFrom <= DateTime.Now && x.ValidTo > DateTime.Now).PositionCustom);

        }).
        ForMember(dest => dest.ClientType,
        opt =>
        {
            opt.MapFrom(y => y.Clients.FirstOrDefault(x => x.ValidFrom <= DateTime.Now && x.ValidTo > DateTime.Now).ClientType);

        })
        .
        ForMember(dest => dest.Documents,
        opt =>
        {
            opt.MapFrom(y => y.Documents.Where(x => x.ValidFrom <= DateTime.Now && x.ValidTo > DateTime.Now));
            //opt.ExplicitExpansion();
        })
        .ForMember(dest => dest.ContactsInfo,
        opt =>
        {
            opt.MapFrom(y => y.ClientContactInfoComps.Where(x => x.ValidFrom <= DateTime.Now && x.ValidTo > DateTime.Now).Select(x => x.ContactInfo));
            //opt.ExplicitExpansion();
        }).
        ForMember(dest => dest.ClientComment,
        opt =>
        {
            opt.MapFrom(y => y.CommentComps.Where(x => x.Contact == null).Select(x => x.Comment));
            //opt.ExplicitExpansion();
        }).
        ForMember(dest => dest.Relations,
        opt =>
        {
            opt.MapFrom(y => y.ClientRelationCompClient1Navigations);
            //opt.ExplicitExpansion();
        })
        ;


        CreateMap<Document, DocumentContract>();

        CreateMap<ContactInfo, ContactInfoContract>().
        ForMember(dest => dest.ContactComments,
        opt =>
        {
        opt.MapFrom(y => y.CommentComps.Select(x => x.Comment));
        });

        CreateMap<ClientRelationComp, RelationContract>().
            ForMember(dest => dest.ClientINN,
            opt => {
                opt.MapFrom(x => x.Client2);
            }).
            ForMember(dest => dest.RelationType,
            opt => {
                opt.MapFrom(x => x.RelationId);
            });

        CreateMap<ICollection<Client>, ClientContract>();
        CreateMap<ICollection<PhysicalPerson>, ClientContract>();
        CreateMap<ICollection<Company>, ClientContract>();
        CreateMap<Comment, CommentContract>();
        CreateMap<ICollection<Comment>, ICollection<ContactInfoContract>>();
        CreateMap<ICollection<ClientRelationComp>, ClientRef>();
        
    }
}

Мой контроллер:

public class ClientContractController : ODataController
{
    CRMContext _context;
    IMapper _mapper;
    public ClientContractController(CRMContext ctx, IMapper mapper )
    {
        _context = ctx;
        _mapper = mapper;
    }

    [EnableQuery(MaxExpansionDepth = 10)]
    public IQueryable<ClientContract> Get()
    {
        return _mapper.ProjectTo<ClientContract>(_context.ClientRefs).Where(x => x.ValidFrom <= DateTime.Now && x.ValidTo >= DateTime.Now);
    }
}

это дает следующее исключение https: // localhost: 44371 / odata / clientcontract? $ expand = Relations

System.InvalidOperationException: выражение LINQ "$ it" не может быть переведено. Либо перепишите запрос в форме, которая может быть переведена, либо явно переключитесь на оценку клиента, вставив вызов AsEnumerable (), AsAsyncEnumerable (), ToList () или ToListAsync (). Видетьhttps://go.microsoft.com/fwlink/?linkid=2101038для дополнительной информации. в Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit (выражение выражения) в Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberAssignment (MemberAssigndingExpressionBisitor.VisitMemberAssignment (MemberAssigninding memberAssignment.MemberAssignment) в System.Assigninding memberAssignment. .Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberInit (MemberInitExpression memberInitExpression) в System.Linq.Expressions.MemberInitExpression.Accept (посетитель ExpressionVisitor) в System.Linq.Expressions.ExpressionVisitor.Visitor.Initance.Visitor (Expressionntity). .Visit (выражение выражения) в System.Linq.Expressions.ExpressionVisitor.VisitLambda [T] (выражение1 node) at System.Linq.Expressions.Expression1.Accept (посетитель ExpressionVisitor) в System.Linq.Expressions.ExpressionVisitor.Visit (узел выражения) в Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit (выражение выражения) в System.Dynamic.Utils.ExpressionVisitorUtils.Visitor , Узлы IArgumentProvider) в System.Linq.Expressions.ExpressionVisitor.VisitMethodCall (узел MethodCallExpression) в System.Linq.Expressions.MethodCallExpression.Accept (посетитель ExpressionVisitor) в System.Linq.Expressions.ExpressionVisitor.Visrame (ExpressionCall .Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit (выражение выражения) в Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberAssignment (MemberAssignment memberAssignment) в System.LindingBindingMember.Visitor.VisitorAssignment .RelationalProjecti onBindingExpressionVisitor.VisitMemberInit (MemberInitExpression memberInitExpression) в System.Linq.Expressions.MemberInitExpression.Accept (посетитель ExpressionVisitor) в System.Linq.Expressions.ExpressionVisitor.Visit (выражение узла выражения) в Microsoft.EntindingFrameworkCore.Quite (выражение узла выражения) в Microsoft.EntindingFrameworkCore.Q ) в Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberAssignment (MemberAssignment memberAssignment) в System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding (MemberBinding node) в Microsoft.InExpressionBinding.Internal.InindingMemberBinding. Linq.Expressions.MemberInitExpression.Accept (посетитель ExpressionVisitor) в System.Linq.Expressions.ExpressionVisitor.Visit (узел выражения) в Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit (Express ион выражение) в Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Translate (SelectExpression selectExpression, выражение Выражения) в Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateSelect (источник ShapedQueryExpression, селектор LambdaExpression) в Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall ( MethodCallExpression methodCallExpression) в System.Linq.Expressions.MethodCallExpression.Accept (посетитель ExpressionVisitor) в System.Linq.Expressions.ExpressionVisitor.Visit (узел Expression) в Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateorQuery.QueryCompilationContext.CreateorQuery. .EntityFrameworkCore.Storage.Database.CompileQuery [TResult] (запрос выражения, логический асинхронный) в Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore [TResult] (база данных IDatabase, запрос выражения, модель IModel, логическое значение as ync) в Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler. <> c__DisplayClass12_0 1.<ExecuteAsync>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func1 компилятор) в Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync [TResult] (Microsoft.EntityFrameworkCore.FrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync [TResult] (Microsoft.запрос Expression.Framework.InstallationToken. EntityQueryProvider.ExecuteAsync [TResult] (выражение выражения, CancellationToken cancellationToken) в Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable 1.GetAsyncEnumerator(CancellationToken cancellationToken) at Microsoft.AspNetCore.Mvc.Infrastructure.AsyncEnumerableReader.ReadInternal[T](Object value) at Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsyncEnumerable(ActionContext context, ObjectResult result, Object asyncEnumerable, Func2 Reader) в Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvokervoker.g__Log (Microsoft.Infrastructure.ResourceInvokervoker.g__0) в Microsoft.ResourceInvoker. AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited | 29_0 [TFilter, TFilterAsync] (вызывающий ResourceInvoker, задача lastTask, состояние далее, область действия, состояние объекта, логическое значение isCompleted) в Microsoft.AspNetCore.Mvc.Infracted context (ResourceInvoker context.Resource ) в Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext [TFilter, TFilterAsync] (State & next, Scope & sc ope, Object & state, Boolean & isCompleted) в Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters () --- Конец трассировки стека из предыдущего места, где было создано исключение --- в Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker. g__Awaited | 19_0 (вызывающий ResourceInvoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) в Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged | 17_1 (ResourceInvoker invokerdle) в Microsoft.AspNetCorequer.me | 6_0 (конечная точка конечной точки, задача requestTask, регистратор ILogger) в Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke (контекст HttpContext) в Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke (контекст HttpContext)

Ответы

MichaelWang Aug 20 2020 at 15:46

Обновление 21.08.20202

Без явного указания , AutoMapperрасширятся все члены в результате.

Чтобы контролировать, какие элементы раскрываются во время проецирования, задайте ExplicitExpansionв конфигурации, а затем передайте элементы, которые вы хотите явно развернуть:

dbContext.Orders.ProjectTo<OrderDto>(configuration,
    dest => dest.Customer,
    dest => dest.LineItems);
// or string-based
dbContext.Orders.ProjectTo<OrderDto>(configuration,
    null,
    "Customer",
    "LineItems");
// for collections
dbContext.Orders.ProjectTo<OrderDto>(configuration,
    null,
    dest => dest.LineItems.Select(item => item.Product));



При использовании используйте имя свойства, а не имя атрибута OData.

ODataклиентская библиотека полагается на свой собственный атрибут, OriginalNameAttributeчтобы получить информацию об именах классов / членов по мере их передачи сервером. Подробности вы можете увидеть здесь .