IQueryable中嵌套Any方法为何仅支持内联Func?
从IQueryable消费者视角分析三种LINQ写法的差异
已知Any方法接受Func<MyChildEntity, bool>参数而非Expression<Func<MyChildEntity, bool>>,但以下三种写法表现不同,从NHibernate这类IQueryable消费者的视角,差异如下:
可行写法
var entities = session.Query<MyEntity>() .Where(m => m.Children.Any(s => s.Prop == "test")) .ToListAsync();
不可行写法1
Func<MyEntityChild, bool> childFunc = m => m.Prop == "test"; var entities = session.Query<MyEntity>() .Where(m => m.Children.Any(childFunc)) .ToListAsync();
不可行写法2
var entities = session.Query<MyEntity>() .Where(m => m.Children.Any(s => childFunc(s))) .ToListAsync();
核心差异分析
可行写法的表达式树完整可解析:
内嵌的s => s.Prop == "test"会被编译成完整的表达式树结构,NHibernate可以遍历这棵树的每个节点,识别出“检查子实体的Prop属性等于'test'”的逻辑,进而将整个LINQ查询转换成对应的SQL(比如生成EXISTS子查询关联父子表,匹配属性条件)。不可行写法的委托是黑盒IL代码:
后两种写法中,childFunc是已经编译完成的委托实例(IL代码),NHibernate拿到的表达式树里,只能看到“调用了一个外部委托”的节点,无法解析委托内部的判断逻辑——它没办法把IL代码反编译成可映射为SQL的条件,自然无法生成正确的查询语句,最终导致执行失败。
内容的提问来源于stack exchange,提问作者Carlo Arnaboldi
相关产品推荐
相关产品推荐

