我有一个关于转换Linq表达式的棘手问题。我有一个很好的搜索,但我找不到任何似乎涵盖这种情况。我对Linq相当熟悉,至少在创建和传递lambda到方法方面,但我对Expression的东西有点弱。
首先,一些上下文:我有一个基于NHibernate的通用持久性解决方案,在许多DDD-ish项目中使用。对于特定情况,聚合中的给定子集合可能基本上是无限的(即确实非常大),我不能简单地映射集合或包,因为将整个集合加载到内存中永远不可接受。在这种体系结构中,使用API的代码不可能直接与存储库通信来执行查询或以这种方式限制结果。我当然可以在API中没有集合,并且公开方法来检索子对象的相关子集(如果这不起作用,那就是我将要做的),但我正在尝试做一些稍微不同的事情而我几乎让它运转起来......
这些项目正在使用Fluent(非自动映射)进行映射,因此我在表单
中添加了一个方法到我的基本地图类HasManyQueryable<TCollection>(Expression<Func<T, IQueryable<TCollection>>> memberExpression, Expression<Func<T, TCollection, bool>> selector)
此方法从第一个PropertyInfo
(指定要映射的成员)派生相关Expression
。选择器Expression
包含父对象和子对象之间的关系,以替代正常的NHibernate映射。
所以,假设我在地图中有一个域名类型User
(上面是T
)的选择器:
HasManyQueryable<Transaction>(x => x.Transactions, (u, t) => t.User == u);
这指定了所有Transactions
的子集之间的映射,其中Transaction.User
是提供的User
u ,而User.Transactions
属性是IQueryable<Transaction>
。当构造一个实际的User
对象时,我需要将其转换为
Expression<Func<Transaction, bool>> expression = (t => t.User == this)
其中this
是正在构造的User
对象。换句话说,我想采用一般规则说明如何将Users
映射到Transactions
并将其转换为关于将此 User
映射到{的规则{1}}。然后,我可以使用此表达式通过执行Linq查询从存储库生成Transactions
,因此:
IQueryable<Transaction>
这只能在选择器为return Repository.For<Transaction>().Where(selector);
时才有效,因此我最终需要转换原始表达式,这会将Func<Transaction, bool>
生成为Func<User, Transaction, bool>
。
这给了我一个Func<Transaction, bool>
集合,其中所有查询操作都是作为Linq-to-NHibernate查询完成的,因此整个集合永远不会被加载到内存中(是的,我知道你可以构建一个查询,实际上是这样做的,但我可以在代码审查时抓住那些。)
呼。希望这是有道理的。
任何有leet表达重写技巧的人能指出我正确的方向吗?
答案 0 :(得分:1)
老实说,从领域的角度来看,我真的很想你要做的事情。但从代码的角度来看,听起来你需要的只是一个curried函数 - 一个接受用户并生成Func的方法。一个示例方法就是这样,尽管你可以做内联相同的事情:
Func<Transaction,bool> UserSpecificSelector(User user,
Func<User,Transaction,bool> selector)
{
return t => selector(user, t);
}
因此,要获得特定于用户的选择器,您可以...
Func<User, Transaction, bool> selector = // whatever;
User user = //whatever;
Repository.For<Transaction>().Where(t => selector(user, t));
我怀疑你需要直接使用Expression
层次结构,除非你实现自己的查询提供程序,在这种情况下你不是。