NHibernate:从存储库返回完全加载的实例的模式
作为我无尽的受 NHibernate 启发的 DAL 重构炼狱的一部分,我已经开始使用存储库模式来让 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;
}
但这一切似乎有点愚蠢。有人使用稍微优雅一点的图案吗?
爱你们。
大卫
As part of my endless NHibernate-inspired DAL refactoring purgatory, I have started to use the Repository pattern to keep NHibernate at arms length from my UI layer. Here's an example of a Load method from a repository.
public StoredWill Load(int id)
{
StoredWill storedWill;
using (ISession session = NHibernateSessionFactory.OpenSession())
{
storedWill = session.Load<StoredWill>(id);
}
return storedWill;
}
I love the fact that my website doesn't know what an ISession is.
Naturally, I started getting lazy initialisation exceptions because the method above doesn't load the StoredWill, it just returns a proxy. When you access the proxy's properties, you get the exception because you are ro longer within the scope of the ISession. I laughed out loud when I realised what was happening.
I have fixed this with:
public StoredWill Load(int id)
{
StoredWill storedWill;
using (ISession session = NHibernateSessionFactory.OpenSession())
{
storedWill = session.Load<StoredWill>(id);
string iReallyCouldntCareLess = storedWill.TestatorLastName;
}
return storedWill;
}
But it all seems a little silly. Does anyone use a slightly more elegant pattern?
Love you guys.
David
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
使用依赖项注入并通过其构造函数将 ISession 传递给存储库类。这是允许多个存储库参与同一事务的唯一方法。
您的网站应该对 ISession 有一定的了解,因为这是定义事务边界的地方。您可以使用每个请求会话模式,以便仅在 HttpRequest 模块或 Global.asax 中引用 ISession。或者您可以使用框架或采用 NHibernate 并控制页面上的事务。
Use dependency injection and pass an ISession to your repository classes through their constructors. That's the only way to allow multiple repositories to participate in the same transaction.
Your website should have some knowledge of an ISession because that's where the transaction boundaries are defined. You can use session-per-request pattern so that the ISession is only referenced in an HttpRequest module or Global.asax. Or you can use a framework or embrace NHibernate and control transactions on the pages.
查看 ncommon 框架;它有一个很好的获取策略实现,非常适合此类任务。您可以在 作者的文章中详细了解如何实现这一点博客。
我还应该注意到,您的会话使用有点偏离...您确实应该在更高层控制会话的生命周期(例如在控制器或 httpmodule 级别,具体取决于您的前端)。为每个存储库操作打开一个新会话是 nhibernate 世界中的一个主要反模式。
Check out the ncommon framework; it has a nice implementation of fetching strategies that are perfect for this sort of task. You can read more about how this is implemented on the author's blog.
I should also note that your session usage is a little off...you should really be controlling the lifecycle of your session higher up (say at the controller or httpmodule level depending on your front-end). Opening a new session for each repository action is a major anti-pattern in the nhibernate world.
您的部分问题是您使用的是 Session.Load() 而不是 Session.Get()。
请参阅这篇文章
Ayende Rahien - Get、Load 和通过 id 查询之间的区别,深入描述两者。
当您调用 Session.Load() 时,您是在告诉 nhibernate 创建您提供的 Id 的代理对象。执行此操作时,nhibernate 实际上不会调用数据库来检索数据。这意味着如果您Session.Load()使用数据库中不存在的内容,它将抛出异常。由于您在访问对象之前关闭会话,因此您无法访问数据,因为代理会话现已关闭。
一个简单的修复方法是将代码更改为使用 Session.Get()。这将从数据库加载您的 StoredWill 类,并用它需要的数据填充您的对象。但请注意,如果您的对象中有任何内部类或集合,它只会为它们创建代理。如果您需要一次性获取所有内容,您可以使用众多查询机制之一来预先加载您需要的部分或使用投影。
我希望这是有道理的:)
Part of you problem is that you're using Session.Load() instead of Session.Get().
see this article by
Ayende Rahien - The difference between Get, Load and querying by id for a in-depth description of the two.
When you call Session.Load() you're telling nhibernate to create a proxy object of the Id that you supply. When doing this nhibernate will not actually call the database to retrive the data. This means that if you Session.Load() with something that does not exits in the database it will throw a Exception. Because you're closing your session before your accessing the object you can't access the data because the proxys session is now closed.
A simple fix would be to change your code to use Session.Get(). This will load your StoredWill class from the database and fill your object with the data that it needs. Note however if you have any inner classes or collections inside you object it will simply create proxies for those. If you need to get everything in one go, you can using one of the many query mechanisims to eager load the parts you need or use projections.
I hope this makes sense :)