作为我无休止的受NHibernate启发的DAL重构炼狱的一部分,我已经开始使用Repository模式来保持NHibernate与我的UI层保持一定距离。以下是存储库中Load方法的示例。
public StoredWill Load(int id)
{
StoredWill storedWill;
using (ISession session = NHibernateSessionFactory.OpenSession())
{
storedWill = session.Load<StoredWill>(id);
}
return storedWill;
}
我喜欢我的网站不知道ISession是什么的事实。
当然,我开始得到延迟初始化异常,因为上面的方法没有加载StoredWill,它只返回一个代理。当您访问代理的属性时,您会得到异常,因为您在ISession的范围内更长。当我意识到发生了什么事时,我大笑起来。
我已修复此问题:
public StoredWill Load(int id)
{
StoredWill storedWill;
using (ISession session = NHibernateSessionFactory.OpenSession())
{
storedWill = session.Load<StoredWill>(id);
string iReallyCouldntCareLess = storedWill.TestatorLastName;
}
return storedWill;
}
但这一切似乎有点愚蠢。有没有人使用稍微优雅的模式?
爱你们。
大卫
答案 0 :(得分:4)
使用依赖注入并通过其构造函数将ISession传递给存储库类。这是允许多个存储库参与同一事务的唯一方法。
您的网站应该具有ISession的一些知识,因为这是定义事务边界的地方。您可以使用每个请求的会话模式,以便仅在HttpRequest模块或Global.asax中引用ISession。或者您可以使用框架或拥抱NHibernate并控制页面上的事务。
答案 1 :(得分:1)
查看ncommon framework;它有一个很好的抓取策略实现,非常适合这种任务。您可以在author's blog上详细了解如何实施此功能。
我还应该注意你的会话使用情况有点偏离......你应该真正控制你的会话的生命周期更高(比如在控制器或httpmodule级别,具体取决于你的前端)。为每个存储库操作打开一个新会话是nhibernate世界中的一个主要反模式。
答案 2 :(得分:1)
public StoredWill Load(int id)
{
StoredWill storedWill;
using (ISession session = NHibernateSessionFactory.OpenSession())
{
storedWill = session.Load<StoredWill>(id);
// force an eager load within the session
NHibernateUtil.Initialize(storedWill.TestatorLastName);
}
return storedWill;
}
答案 3 :(得分:0)
部分问题是您使用 Session.Load()而不是 Session.Get()。
看到这篇文章 Ayende Rahien - The difference between Get, Load and querying by id有关这两者的深入描述。
当您调用 Session.Load()时,您告诉nhibernate创建您提供的Id的代理对象。执行此操作时,nhibernate实际上不会调用数据库来检索数据。这意味着,如果 Session.Load()包含未在数据库中退出的内容,则会抛出异常。因为您在访问对象之前关闭了会话,所以无法访问数据,因为代理会话现已关闭。
一个简单的解决方法是将代码更改为使用 Session.Get()。这将从数据库加载StoredWill类,并使用所需的数据填充对象。但是请注意,如果您在对象内部有任何内部类或集合,它将只为这些创建代理。如果您需要一次性获取所有内容,则可以使用众多查询机制之一来急切加载您需要的部分或使用投影。
我希望这是有道理的:)