Web API Queryable - how to apply AutoMapper?

前端 未结 4 1157
一整个雨季
一整个雨季 2020-11-30 23:03

I\'ve got a simple WebApi method like this decorated with the OData queryable attribute.

    [Queryable]
    public virtual IQueryable Get()         


        
4条回答
  •  不知归路
    2020-11-30 23:39

    IMHO the accepted solution is not correct. Generally speaking, if your service is using DTOs, you don't want to expose the underlying Entities (Person) to the service. Why would you query against the Person model and return PersonDTO objects?

    Since you're already using it, Automapper has Queryable Extensions which allows you to expose only your DTOs and have the filtering applied to the underlying type at the data source. For example:

    public IQueryable Get(ODataQueryOptions options) {
        Mapper.CreateMap();
        var persons = _personRepository.GetPersonsAsQueryable();
        var personsDTOs = persons.Project().To();  // magic happens here...
    
        return options.ApplyTo(personsDTOs);
    }
    

    Regarding eagerly loading navigation properties...

    @philreed: I couldn't put a decent response in the comment so I added it here. There was a post on how to do this here but I'm getting 403s today. Hopefully that's temporary.

    Basically, you examine the Select and Expand clauses for your navigation property. If it is present, then you tell EF to eagerly load via IQueryable Include extension method.

    Controller

    public IQueryable GetMyDtos(ODataQueryOptions options)
    {   
      var eagerlyLoad = options.IsNavigationPropertyExpected(t => t.MyNavProperty);
      var queryable = _myDtoService.GetMyDtos(eagerlyLoad);
    
      // _myDtoService will eagerly load to prevent select N+1 problems
      // return (eagerlyLoad) ? efResults.Include(t => t.MyNavProperty) : efResults;
    
      return queryable;
    }
    

    Extension method

    public static class ODataQueryOptionsExtensions
    {
      public static bool IsNavigationPropertyExpected(this ODataQueryOptions source, Expression> keySelector)
      {
        if (source == null) { throw new ArgumentNullException("source"); }
        if (keySelector == null) { throw new ArgumentNullException("keySelector"); }
    
        var returnValue = false;
        var propertyName = (keySelector.Body as MemberExpression ?? ((UnaryExpression)keySelector.Body).Operand as MemberExpression).Member.Name;
        var expandProperties = source.SelectExpand == null || string.IsNullOrWhiteSpace(source.SelectExpand.RawExpand) ? new List().ToArray() : source.SelectExpand.RawExpand.Split(',');
        var selectProperties = source.SelectExpand == null || string.IsNullOrWhiteSpace(source.SelectExpand.RawSelect) ? new List().ToArray() : source.SelectExpand.RawSelect.Split(',');
    
        returnValue = returnValue ^ expandProperties.Contains(propertyName);
        returnValue = returnValue ^ selectProperties.Contains(propertyName);
    
        return returnValue;
      }
    }
    

提交回复
热议问题