ExplicitExpansion () fait que l'extension OData ne fonctionne pas

Aug 20 2020

Lorsque vous utilisez ExplicitExpansion (), Odata expand ne fonctionne pas. Mes modèles DTo et EF peuvent être trouvés ci-dessous le lien. Interroger les DTO basés sur EF à l'aide d'Odata

Ma classe 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>();
        
    }
}

Mon contrôleur:

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);
    }
}

cela donne l'exception suivante https: // localhost: 44371 / odata / clientcontract? $ expand = relations

System.InvalidOperationException: L'expression LINQ '$ it' n'a pas pu être traduite. Réécrivez la requête sous une forme qui peut être traduite ou basculez explicitement vers l'évaluation du client en insérant un appel à AsEnumerable (), AsAsyncEnumerable (), ToList () ou ToListAsync (). Voirhttps://go.microsoft.com/fwlink/?linkid=2101038pour plus d'informations. à Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit (Expression expression) à Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberAssignment (MemberAssignment memberAssignitor.Visit (Expression expression) à Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberAssignment (MemberAssignment memberAssignitor.RameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor. .Query. .Visit (Expression expression) à System.Linq.Expressions.ExpressionVisitor.VisitLambda [T] (Expression1 node) at System.Linq.Expressions.Expression1.Accepter (visiteur ExpressionVisitor) sur System.Linq.Expressions.ExpressionVisitor.Visit (nœud Expression) sur Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit (Expression expression) sur System.Dynamic.Utils.ExpressionVisitorUtils.Visit. , IArgumentProvider nodes) chez System.Linq.Expressions.ExpressionVisitor.VisitMethodCall (node ​​MethodCallExpression) chez System.Linq.Expressions.MethodCallExpression.Accept (ExpressionVisitor) chez System.Linq.Expressions.ExpressionVisitor.Visit (ExpressionVisitor) chez System.Linq.Expressions.ExpressionVisitor.Visit (ExpressionVisitor node) .Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit (Expression expression) sur Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberAssignment (MemberAssignment memberAssignment) sur System.Linq.Expressions.ExpressionVisemberity.Visemberity.Visemberity.Visemberity.Visemberity.Visemberity. .Projet relationnel onBindingExpressionVisitor.VisitMemberInit (MemberInitExpression memberInitExpression) à System.Linq.Expressions.MemberInitExpression.Accept (ExpressionVisitor visiteur) à System.Linq.Expressions.ExpressionVisitor.Visit (noeud Expression) à Microsoft.EntityFrameworkCore.Expression.Expression.Expression.Expression.Expressionational.Query ) à Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberAssignment (MemberAssignment memberAssignment) à System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding (nœud MemberBinding) à Microsoft.EntityFrameworkCommercialIntityFrame.ExpressionInterminable. Linq.Expressions.MemberInitExpression.Accept (visiteur ExpressionVisitor) à System.Linq.Expressions.ExpressionVisitor.Visit (nœud d'expression) à Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit (Express ion expression) chez Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Translate (SelectExpression selectExpression, Expression expression) chez Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateSelectExpressionVisitor.Translate (SelectExpression selectExpression, Expression expression) chez Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateSelect (source). MethodCallExpression methodCallExpression) à System.Linq.Expressions.MethodCallExpression.Accept (visiteur ExpressionVisitor) à System.Linq.Expressions.ExpressionVisitor.Visit (noeud Expression) à Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQuery [TReseryExpression] à Microsoft. .EntityFrameworkCore.Storage.Database.CompileQuery [TResult] (Expression query, Boolean async) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore [TResult] (base de données IDatabase, Expression query, IModel model, Boolean as ync) chez Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler. <> c__DisplayClass12_0 1.<ExecuteAsync>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func1 compilateur) chez Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync [TResult] (Expression query, CancellationTokenEnameTokenToken). EntityQueryProvider.ExecuteAsync [TResult] (Expression expression, CancellationToken cancelToken) sur 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) sur Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged | 21_esoker sur ResourceInvoker. AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited | 29_0 [TFilter, TFilterAsync] (ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) chez Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvealedExecuted context (ResultSecuted) ) sur Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext [TFilter, TFilterAsync] (State & next, Scope & sc ope, Object & state, Boolean & isCompleted) à Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters () --- Fin de la trace de pile à partir de l'emplacement précédent où l'exception a été levée --- à Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker. g__Awaited | 19_0 (Invocateur ResourceInvoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) sur Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged | 17_1 (ResourceInvoker invoker) sur Microsoft.AspNetCore.Routing.TwaitMiddle__ | 6_0 (Endpoint endpoint, Task requestTask, ILogger logger) sur Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke (contexte HttpContext) sur Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke (contexte HttpContext)

Réponses

MichaelWang Aug 20 2020 at 15:46

Mise à jour 21/08/20202

Sans instructions explicites , AutoMapperdéveloppera tous les membres dans le résultat.

Pour contrôler quels membres sont développés pendant la projection, définissez-les ExplicitExpansiondans la configuration, puis transmettez les membres que vous souhaitez développer explicitement:

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));



Utilisez le nom de la propriété et non l'attribut Name lors de l'utilisation OData.

ODatala bibliothèque cliente s'appuie sur son propre attribut OriginalNameAttributepour acquérir des connaissances sur les noms de classe / membre lorsque le serveur les émet. Les détails que vous pouvez voir d' ici .