请参阅下面的代码:
public Enquiry GetByID(Guid personID)
{
using (IUnitOfWork<ISession> unitOfWork = UnitOfWorkFactory.Create())
{
IRepository repository = RepostioryFactory.Create(unitOfWork);
var Person = repository.GetById(personID);
return Person;
}
}
它包含在应用程序服务层中。 人员被传递回控制器并加载到视图中。 然后,视图出错,因为它无法加载 Person.Collection(列表)。
我相信这是因为集合是使用延迟加载加载的,一旦到达视图,工作单元和 NHibernate 会话就会关闭。 在这种情况下,我必须使用紧急加载还是误解了什么?
恕我直言,懒惰加载是邪恶的!
存储库背后的想法是返回聚合。 该汇总应包含构成聚合的所有相关数据。 它永远不会以位为单位加载。 因此,应该始终急切地获取聚合。
如果您从等式中删除 UoW/ORM,则延迟加载不是一种选择。
您应该尽量不要查询您的域。 如果单个聚合包含所需的所有数据并且该数据已公开,则可以。
但是,我建议您使用读取模型。 一个简单的查询图层。 试一试,你可能会感到惊讶:)
我意识到会话在方法完成之前结束(它包装在using
块中),也就是在您的视图代码运行之前。所以是的,你确实需要预先加载集合属性中的项目,以你从 NHibernate 会话返回的Enquiry
类型。
更好的方法是设置工作单元模式,使其在管道中环绕整个请求。例如,如果您有一个Global.asax
文件,则它有两个方法,分别称为 Application_BeginRequest
和 Application_EndRequest
。
Application_BeginRequest
方法将创建一个新的 NHibernate 会话,控制器可以检索该会话。
Application_EndRequest
方法只需刷新会话,将任何数据更改保存到基础数据库。
我向您推荐以下 StackOverflow 问题,用于将 NHibernate 会话与 Global.asax
组件合并:global.asax Application_BeginRequest中的 NHibernate Session
引入视图模型层而不是将原始实体传递给控制器将解决您的问题,因为映射到Person
视图模型(在 using
子句内)将访问Person.Collection
并触发加载。
或者,你可以有一个不通过域的整个读取端,正如@EbenRoux所建议的那样。
在这种情况下,我必须使用紧急加载还是误解了什么?
好吧,你想,不是吗? 您处于一个用例中,您知道您希望 Person.Collection 可用,那么为什么不立即加载它。
诀窍是不要使用您希望延迟加载集合(或根本不加载)时使用的相同存储库实现。
乌迪·达汉(Udi Dahan)多次写过这个问题
- http://udidahan.com/2007/03/06/better-domain-driven-design-implementation/
- http://udidahan.com/2007/04/23/fetching-strategy-design/
Greg Young 会提醒您,使用获取策略是一个实现细节,而不是合同的一部分
- http://codebetter.com/gregyoung/2009/01/16/ddd-the-generic-repository/