我正在使用自动生成的 OData 客户端,我正在尝试创建一个通用的客户端类。
我想通过一些谓词。
public T Get<T>(Func<T, bool> predicate)
{
var entityName = GetEntitySetName<T>();
var query = _d365Context.CreateQuery<T>(entityName);
return query.Where(predicate).FirstOrDefault();
}
private static string GetEntitySetName<T>()
{
var originalEntitySetName = typeof(T).GetCustomAttributes(typeof(EntitySetAttribute), true).Cast<EntitySetAttribute>().SingleOrDefault()?.EntitySet;
return originalEntitySetName;
}
此代码正在读取所有数据而不是应用谓词。 我已经尝试过的。
所以我的问题是,是否有可能实现我想要做的事情? 有现成的图书馆吗?
PS - 我不想使用 Simple.Odata.Client
一个想法在我脑海中流动,使用谓词并以某种方式解析它并在 AddQueryOption 中使用它(此方法采用字符串名称和对象值)。但我对 Func 没有太多经验,所以不确定是否可以完成。
你应该把你的
Func<T, bool>
换成表情:
public T Get<T>(Expression<Func<T, bool>> predicate)
{
var entityName = GetEntitySetName<T>();
var query = _d365Context.CreateQuery<T>(entityName);
return query.Where(predicate).FirstOrDefault();
}
原因是不能以这种方式构造查询以从委托在数据库端执行。然而,如果你把它包装成一个表达式树,它就可以被正确地分析和转换。
相同的规则适用于
OData
协议 - 如果您想直接从源获取过滤后的数据,您应该使用 IQueryable<T>
从表达式构造而不是 IEnumerable<T>
从委托转换。
使用
Func
使您的查询切换到 IEnumerable
所以它需要获取所有数据。 OData 需要与 IQueryable
一起工作才能翻译查询(同样适用于基于 LINQ 的 ORM,如 EF Core)。来自 OData 文档(假设您正在使用它,如果不是相同的规则适用于其他IQueryable
提供商):
由于
类实现了DataServiceQuery<TElement>
接口,OData 客户端库能够将针对实体集的 Linq 查询转换为针对数据服务资源执行的 URI。IQueryable<T>
所以你需要使用表达式树而不是简单的函数:
public T Get<T>(Expression<Func<T, bool>> predicate)
{
var entityName = GetEntitySetName<T>();
var query = _d365Context.CreateQuery<T>(entityName);
return query.Where(predicate).FirstOrDefault();
}
阅读更多: