使用自动生成OData Client时,CreateQuery<T>未应用谓词求助
问题描述
我正在使用自动生成的OData Client,尝试创建一个通用客户端类,希望通过谓词筛选获取数据。编写的代码如下:
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; }
但这段代码会读取全部数据,并未应用谓词筛选。我已尝试过这些方案:
- 知道query有AddQueryOption方法,但不想使用;
- 可以直接使用context.EntityName,但这会硬编码实体名。
我的问题是:能否实现我想要的功能?有没有可用的现有库?
注:不想使用Simple.Odata.Client。
另外我有一个思路:解析谓词并用于AddQueryOption(该方法接收字符串名称和对象值),但我对Func经验不足,不确定是否可行。
解决方案
为什么当前代码会全量读取数据
你用的Func<T, bool>是LINQ to Objects的委托,它会把OData返回的所有数据拉到本地后再执行筛选,而不是把筛选条件转换成OData的$filter语句发送到服务端,这就是导致全量读取的核心原因。要实现服务端筛选,必须用表达式树Expression<Func<T, bool>>替代普通委托。
实现通用服务端筛选的最优方案
- 改用Expression<Func<T, bool>>作为参数
自动生成的OData Client上下文的CreateQuery<T>返回的是IQueryable<T>,它原生支持表达式树解析,可以把Expression直接转换成OData的$filter参数发送到服务端。修改后的代码如下:
public T Get<T>(Expression<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; }
这个方案无需额外库,直接利用OData Client的原生能力,既实现了服务端筛选,又保持了实体名的自动获取,完全避免硬编码。
关于你提到的解析Func的思路
解析Func<T, bool>转成AddQueryOption参数的思路可行,但完全没必要——因为Func是编译后的委托,没有表达式树的结构信息,解析需要通过IL反编译等复杂手段,远不如直接用Expression<Func<T, bool>>简洁高效。可选的辅助库(无需Simple.OData.Client)
如果需要构建更复杂的OData查询,可以考虑:
- Microsoft.OData.Client:就是你当前使用的自动生成客户端的基础库,本身已支持表达式树转OData查询,无需额外引入;
- ODataQueryBuilder:轻量的OData查询构建库,可辅助生成复杂的
$filter语句,但对你的场景来说,原生表达式树方案已经足够满足需求。
关键注意点
- 确保自动生成的实体类上正确标记了
EntitySetAttribute,否则GetEntitySetName<T>可能返回null,导致查询失败; - 并非所有.NET表达式都能被OData Client转换成有效的
$filter语句,比如自定义方法调用、过于复杂的条件嵌套可能无法解析,需要遵循OData协议支持的运算符和函数规范。
内容的提问来源于stack exchange,提问作者Manish
相关产品推荐
相关产品推荐

