gpt4 book ai didi

c# - 如何获取 OData 可查询 Web API 端点过滤器并将其映射到 DTO 对象?

转载 作者:行者123 更新时间:2023-11-30 16:38:21 24 4
gpt4 key购买 nike

我有一个简单的 Web API 端点,可以接受传入的 OData 查询:

public IActionResult GetProducts(ODataQueryOptions<ProductDTO> options)
{
var results = DomainLayer.GetProducts(options);
return Ok(results);
}

我特别希望能够针对 ProductDTO 进行查询对象,并能够根据 DTO 表示的属性进行过滤或排序。

我的设计问题是我想利用 OData 库的过滤器解析/应用逻辑,但我不想公开我的数据库绑定(bind) ProductEntity反对我的 Web API AND 我不想返回 IQueryable来 self 的 DataAccessLayer , 只有 IEnumerable

然后我要做的是提取 Expression来自 FilterQueryOption传入属性ODataQueryOptions所以我可以使用 AutoMapper 的表达式映射功能来映射 Expression<Func<ProductDTO, bool>> 中的表达式到 Expression<Func<Product, bool>>然后最后到Expression<Func<ProductEntity, bool>>然后我将把它传递到 .Where() 中调用我Table<ProductEntity> 在我的 SQL 数据库(通过 Linq-2-SQL)中(希望)应用过滤器的位置然后我将它一直转换回 DTO 对象。

我遇到的最大障碍是 queryable.Expression正在返回 MethodCallExpression而不是 Expression<Func<ProductDTO, bool>>如我所料,这意味着我无法像我计划的那样使用 AutoMapper 映射表达式...

我该如何解决这个问题?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.AspNet.OData.Query;
using AutoMapper.Extensions.ExpressionMapping;
using AutoMapper.QueryableExtensions;

namespace ProductApp
{
public class DomainLayer
{
public IEnumerable<ProductDTO> GetProductsByEntityOptions(ODataQueryOptions<ProductDTO> options)
{
var mapper = MyMapper.GetMapper();

// This is the trick to get the expression out of the FilterQueryOption...
IQueryable queryable = Enumerable.Empty<ProductDTO>().AsQueryable();
queryable = options.Filter.ApplyTo(queryable, new ODataQuerySettings());
var exp = (MethodCallExpression) queryable.Expression; // <-- This comes back as a MethodCallExpression...

// Map the expression to my intermediate Product object type
var mappedExp = mapper.Map<Expression<Func<Product, bool>>>(exp); // <-- But I want it as a Expression<Func<ProductDTO, bool>> so I can map it...

IEnumerable<Product> results = _dataAccessLayer.GetProducts(mappedExp);

return mapper.Map<IEnumerable<ProductDTO>>(results);
}
}

public class DataAccessLayer
{
public IEnumerable<Product> GetProducts(Expression<Func<Product, bool>> exp)
{
var mapper = MyMapper.GetMapper();

var mappedExp = mapper.Map<Expression<Func<ProductEntity, bool>>>(exp);
IEnumerable<ProductEntity> result = _dataContext.GetTable<ProductEntity>().Where(mappedExpression).ToList();

return mapper.Map<IEnumerable<Product>>(result);
}
}
}

引用资料:

最佳答案

嗯,accepted answer的作者|最后写的链接帖子:

Notice that the expression contains looks more like this, SOTests.Customer[].Where($it => conditional-expression). So, you might have to extract that conditional expression from the 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 ...
}
}

关于c# - 如何获取 OData 可查询 Web API 端点过滤器并将其映射到 DTO 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55307370/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com