在 NHibernate 下加载部分/过滤/基于标准的列表的“正确”方式是使用查询。有,lazy="extra"
但它不做你想要的。
正如您已经注意到的那样,这打破了根聚合 -> 子级的 DDD 模型。我一直在为这个问题苦苦挣扎,因为首先我讨厌持久性问题污染我的域模型,而且我永远无法让 API 表面看起来“正确”。拥有实体类的过滤器方法工作但远非漂亮。
最后,我决定扩展我的实体基类(我的所有实体都继承自它,我知道这些天有点不合时宜,但它至少让我可以始终如一地做这种事情)使用一个名为Query<T>()
LINQ的受保护方法定义关系的表达式,并在存储库的底层调用 LINQ-to-NH 并返回一个IQueryable<T>
您可以根据需要查询的值。然后,我可以在常规属性下方调用该调用。
基类这样做:
protected virtual IQueryable<TCollection> Query<TCollection>(Expression<Func<TCollection, bool>> selector)
where TCollection : class, IPersistent
{
return Repository.For<TCollection>().Where(selector);
}
(我应该在这里注意到我的 Repository 实现IQueryable<T>
直接实现,然后将工作委托给 NH Session.Query<T>()
)
外墙的工作方式是这样的:
public virtual IQueryable<Form> Forms
{
get
{
return Query<Form>(x => x.Account == this);
}
}
这将 Account 和 Form 之间的列表关系定义为实际映射关系的逆(Form -> Account)。
对于“无限”集合 - 集合中可能存在无限数量的对象 - 这可以正常工作,但这意味着您不能直接在 NHibernate 中映射关系,因此不能直接在 NH 查询中使用该属性,只有间接地。
我们真正需要的是替代 NHibernate 的通用包、列表和集合实现,这些实现知道如何使用 LINQ 提供程序直接查询列表。一个已被提议作为补丁(参见https://nhibernate.jira.com/browse/NH-2319)。正如您所看到的,补丁尚未完成或被接受,并且从我所看到的提议者没有将其重新打包为扩展 - Diego Mijelshon 是这里的用户所以也许他会插话......我有将他提议的代码作为 POC 进行了测试,它确实像宣传的那样工作,但显然它没有经过测试或保证或不一定完整,它可能有副作用,并且未经许可使用或发布它,你无论如何都不能使用它。
直到并且除非 NH 团队开始编写/接受使这种情况发生的补丁,否则我们将不得不继续诉诸变通方法。NH 和 DDD 只是对世界的看法相互矛盾,在这里。