我有一个简单的Web API端点,可以接受传入的OData查询:
public IActionResult GetProducts(ODataQueryOptions<ProductDTO> options)
{
var results = DomainLayer.GetProducts(options);
return Ok(results);
}
我特别希望能够针对ProductDTO
对象进行查询,并能够根据DTO表示的属性进行过滤或排序。
我的设计问题是我想利用OData库的过滤器解析/应用逻辑,但不想将数据库绑定的ProductEntity
对象公开给我的Web API 我不想从我的IQueryable
中仅返回DataAccessLayer
个IEnumerable
。
然后我要做的是从传入的Expression
的{{1}}属性中提取FilterQueryOption
,这样我就可以使用AutoMapper的Expression Mapping功能来映射{ {1}}到ODataQueryOptions
,然后最后到达Expression<Func<ProductDTO, bool>>
,然后将其传递给我的Expression<Func<Product, bool>>
上的Expression<Func<ProductEntity, bool>>
调用(希望)在过滤器中应用于我的SQL数据库中(通过Linq-2-SQL),然后我将其完全转换回DTO对象。
我遇到的最大问题是.Where()
返回的是Table<ProductEntity>
而不是我期望的queryable.Expression
,这意味着我无法像以前那样使用AutoMapper映射表达式计划中的...
我该如何解决?
MethodCallExpression
参考:
答案 0 :(得分:2)
链接文章accepted answer的作者在结尾处写道:
请注意,表达式包含的内容更像
SOTests.Customer[].Where($it => conditional-expression)
。因此,您可能必须从lambda中提取该条件表达式。
您获得的MethodCallExpression
就是这样-对Queryable.Where<ProductDTO>
的“调用”,而您需要的lambda表达式Expression<Func<ProductDTO, bool>>
是第二个参数(记住Queryable.Where
是 static 扩展方法,因此第一个参数表示IQueryable<ProductDTO>
,并用Expression.Quote包装。
因此,您所需要做的就是使用以下内容提取lambda表达式:
public static class ODataQueryOptionsExtensions
{
public static Expression<Func<T, bool>> GetFilter<T>(this ODataQueryOptions<T> options)
{
// The same trick as in the linked post
IQueryable query = Enumerable.Empty<T>().AsQueryable();
query = options.Filter.ApplyTo(query, new ODataQuerySettings());
// Extract the predicate from `Queryable.Where` call
var call = query.Expression as MethodCallExpression;
if (call != null && call.Method.Name == nameof(Queryable.Where) && call.Method.DeclaringType == typeof(Queryable))
{
var predicate = ((UnaryExpression)call.Arguments[1]).Operand;
return (Expression<Func<T, bool>>)predicate;
}
return null;
}
}
并像这样使用它:
public class DomainLayer
{
public IEnumerable<ProductDTO> GetProductsByEntityOptions(ODataQueryOptions<ProductDTO> options)
{
var filter = options.GetFilter();
// Here the type of filter variable is Expression<Func<ProductDTO, bool>> as desired
// The rest ...
}
}