在NHibernate + DDD上下文中重写Linq Expression

时间:2011-08-24 20:07:58

标签: nhibernate linq-expressions

我有一个关于转换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表达重写技巧的人能指出我正确的方向吗?

1 个答案:

答案 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层次结构,除非你实现自己的查询提供程序,在这种情况下你不是。