LINQ表达式扩展方法开发遇阻:需封装Queryable的Where子句
嘿,你已经完成了大部分工作,只差把这些表达式片段组合成最终的查询条件,然后和传入的Layer选择器表达式结合起来啦!我来帮你补全代码并解释关键步骤:
完整的扩展方法实现
using System; using System.Linq; using System.Linq.Expressions; using System.Reflection; public static class QueryableExtensions { public static IQueryable<T> LayerHierarchy<T>(this IQueryable<T> query, Expression<Func<T, Layer>> layerSelector, string hierarchy) { // 1. 获取Layer类型的参数表达式(用于构建Layer层级的条件) var layerParam = Expression.Parameter(typeof(Layer), "layer"); // 2. 构建访问Layer.Hierarchy的表达式 var hierarchyProperty = Expression.Property(layerParam, nameof(Layer.Hierarchy)); // 3. 构建StartsWith条件:layer.Hierarchy.StartsWith(hierarchy) var startsWithMethod = typeof(string).GetMethod(nameof(string.StartsWith), new[] { typeof(string) }) ?? throw new InvalidOperationException("StartsWith method not found on string"); var startsWithValue = Expression.Constant(hierarchy, typeof(string)); var startsWithCall = Expression.Call(hierarchyProperty, startsWithMethod, startsWithValue); // 4. 构建Equals条件:layer.Hierarchy == hierarchy // 用Expression.Equal比直接调用Equals方法更符合LINQ查询习惯,ORM也更容易翻译 var equalsValue = Expression.Constant(hierarchy, typeof(string)); var equalsCondition = Expression.Equal(hierarchyProperty, equalsValue); // 5. 合并两个条件:StartsWith || Equals var combinedLayerCondition = Expression.OrElse(startsWithCall, equalsCondition); // 6. 把Layer层级的条件封装成Lambda:layer => layer.Hierarchy.StartsWith(...) || ... var layerConditionLambda = Expression.Lambda<Func<Layer, bool>>(combinedLayerCondition, layerParam); // 7. 把Layer条件和传入的T->Layer选择器结合,生成针对T的条件 var tParam = layerSelector.Parameters[0]; // 获取原T类型的参数(来自layerSelector表达式) var invokedCondition = Expression.Invoke(layerConditionLambda, layerSelector.Body); // 调用Layer条件Lambda,传入x.Layer var finalCondition = Expression.Lambda<Func<T, bool>>(invokedCondition, tParam); // 生成最终的T类型查询Lambda // 8. 将条件应用到查询上并返回 return query.Where(finalCondition); } }
关键步骤解释
- 替换Equals方法调用:直接用
Expression.Equal替代string.Equals方法调用,更符合LINQ表达式树的规范,大多数ORM(比如EF Core、NHibernate)能更好地将其翻译为SQL语句。 - 合并逻辑条件:通过
Expression.OrElse构建逻辑或关系,完美对应原代码中的||运算符。 - 跨类型表达式组合:利用
Expression.Invoke把针对Layer的条件Lambda,和传入的layerSelector(比如x => x.Layer)结合,生成完整的针对T的查询条件,保证ORM能正确解析整个表达式树。
使用方式
完全符合你预期的简化写法:
var hierarchy = "a string"; var result = Session.Query<SomeClass>().LayerHierarchy(x => x.Layer, hierarchy);
额外注意事项
- 如果你的层级判断实际需要给
hierarchy拼接|(比如层级用|分隔),只需要修改startsWithValue为Expression.Constant($"{hierarchy}|", typeof(string))即可。 - 确保
Layer类的Hierarchy属性是string类型,否则需要调整表达式中的类型处理逻辑。
内容的提问来源于stack exchange,提问作者DontVoteMeDown
相关产品推荐
相关产品推荐

