C# NHibernate生命周期;何时可以在每个存储库方法中创建/处置?
我正在使用单层,单用户应用程序,以及FluentNHibernate。使用多线程,由时间触发器和传入套接字消息触发器触发 什么要求将决定我是否可以在存储库的每个方法中创建/处理ISession,或者我是否需要在多个调用(可能从程序开始到结束)中维护ISession生命周期 例如,延迟加载是否需要维护会话?如果我不使用lazyload,还有什么其他原因我应该保持ISession 目前,我的存储库方法如下所示,但我想知道我是否做错了C# NHibernate生命周期;何时可以在每个存储库方法中创建/处置?,c#,.net,database,nhibernate,repository,C#,.net,Database,Nhibernate,Repository,我正在使用单层,单用户应用程序,以及FluentNHibernate。使用多线程,由时间触发器和传入套接字消息触发器触发 什么要求将决定我是否可以在存储库的每个方法中创建/处理ISession,或者我是否需要在多个调用(可能从程序开始到结束)中维护ISession生命周期 例如,延迟加载是否需要维护会话?如果我不使用lazyload,还有什么其他原因我应该保持ISession 目前,我的存储库方法如下所示,但我想知道我是否做错了 public class ProductRepository {
public class ProductRepository
{
public void Delete(Product product)
{
using (ISession session = FNH_Manager.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
session.Delete(product);
transaction.Commit();
}
}
}
class FNH_Manager
{
private static Configuration cfg;
private static ISessionFactory sessionFactory;
public static void ConfigureSessionFactory()
{
sessionFactory = CreateSessionFactory();
}
public static ISession OpenSession()
{
return sessionFactory.OpenSession();
}
EDIT1: 尝试处理“每次呼叫会话”:
当您引用延迟加载字段时,会话必须打开,因此如果您依赖于存储库外部的延迟加载,则需要在更高的位置管理会话寿命
如果不使用延迟加载,那么还有一个问题,即是否需要在一个事务中支持多个操作。例如,如果一次删除一个产品和一些其他数据,您希望在同一会话中的一个事务中发生这种情况(否则您可能会删除该产品,让一些代码引发一些异常,并且永远不会删除其他数据,这可能会导致孤立记录或数据库中的损坏状态).删除时,产品与任何会话均不关联。这就是所谓的分离对象。要在会话中使用它,例如删除它,您需要首先将它与当前打开的会话相关联。有几种方法可以实现这一点:
ISession.Get()
或ISession.Load()
session
StaleStateException
s等等
请记住阅读我认为每个线程应该使用UnitOfWork模式。
在线程启动时,创建ISession并用它初始化UnitOfWork。存储库将
UnitOfWork
与该符号ISession
一起使用。在线程执行结束时,如果与其他线程发生冲突,请提交更改或回滚。省去麻烦,只需实现一个工作单元来管理会话即可。它很可能最终实际上是更少的代码,如果应用程序变得更复杂,您需要促进从不同存储库检索到的多个实体之间的复杂交互,那么它将被放大。@Brook-会话已经是一个工作单元。@Phil-它是,但它不会自动为您包装一组更改。为此,我通常将其包装在一个类中,该类将其范围限定为特定的web或wcf请求,并将其称为工作单元。另一件事是,我通常不希望应用程序的这些部分依赖于NH,因此包装器也允许您将其解耦。好的,我明白你的意思,现在更有意义了。我不确定如何实现这一点,每个线程都可以在我的业务逻辑中启动一系列事件,在不同的地方可能会触发对数据库的保存。我不知道如何从这个角度“坚持”一节课因此,对于我来说,从“每次调用会话”开始似乎更容易,除非这在多线程方面存在一些固有问题。@bretdog管理会话范围的一种常见方法是允许依赖项注入容器(如StructureMap或Ninject)为您处理该问题。任何现代的容器都有为您管理“每线程”、“每请求”、“单例”的工具,所以您不必担心它。@Brook:您知道这些词“依赖注入”甚至“容器”都不是我知道的意思。当您考虑一个类时,可能会模糊地持有一个会话字段(?),它可以注入会话,但我不确定它应该是什么类,因为在线程操作中涉及大量的类,并且许多类可以命中数据库。所以我真的不知道该怎么做。因此,作为一个开始,我的动机是“每次通话会话”。@bretdog:我认为每次通话会话都会很快发现问题。您基本上放弃了使用事务保持数据库处于一致状态的能力。延迟加载可能会继续成为一个问题,因为会话的作用域将无法正确确定。在我看来,提前学习更好的方法是值得的。我想知道这是否合理,但我有一大堆事情要完成,所以需要优先考虑。尽管我确实想听听是否有令人信服的理由;但是我不会使用懒惰加载。。所以我真的看不出这对我有什么意义?我的意思是许多DAL与DTO一起工作,所以处理分离的实体会有那么难吗?在我看来,这似乎仍然是不那么复杂的解决方案。谢谢!这三点真的很有帮助!我也阅读了文档,所以现在了解更多。我上面的编辑是否适合此目的?用ISession.Lock;您的意思是这就是我将在存储库的更新方法中对分离实例使用的方法吗?由于它似乎与“删除”无关,如果我理解的文档正确吗?很高兴帮助!虽然增加会话范围以使第一次加载和删除在同一个会话中被认为是最佳做法,但编辑看起来还可以。第一次加载发生在第一次从数据库获取产品时代码示例开始之前。ISession.Lock方法的名称不是很好。它将重新连接实体,以便操作
public class EmployeeRepository
{
public static void Delete(Employee employee)
{
using (ISession session = FNH_Manager.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
if (Employee.Id != 0)
{
var emp = session.Get(typeof(Employee), employee.Id);
if (emp != null)
{
session.Delete(emp);
transaction.Commit();
}
}
}
}
}