【问题标题】:NHibernate GenericRepo Memory LeakNHibernate GenericRepo 内存泄漏
【发布时间】:2014-02-10 17:45:33
【问题描述】:

我一直在使用通用存储库和 NHibernate,但在阻止内存泄漏/保持会话打开时遇到问题。

方法是

public IQueryable<TEntity> Find()
{
   ISession session = _sessionFactory.OpenSession();
   return session.Query<TEntity>();
}

显然这会使会话保持打开状态,但是当我使用以下功能时

public IQueryable<TEntity> Find()
{
   using (ISession session = _sessionFactory.OpenSession())
   {
       return session.Query<TEntity>();
   }
}

运行查询时会话关闭。

在查询运行后我是否可以处理会话??

这个方法的调用是这样的:

MyRepo repo = new MyRepo();
var list = repo.MyEntity.Find().Where(e => e.Id ==0).First();
//Need to dispose here????

这可以在调用方法不需要显式处理的情况下完成吗? IE。我想避免。

MyRepo repo = new MyRepo();
var list = repo.MyEntity.Find().Where(e => e.Id ==0).First();
repo.DisposeSession();

提前致谢。

编辑

这里是 repo 类

public NHibernateRepo<TEntity> : IRepo<TEntity> where TEntity : class
{
     private readonly SessionFactory _sessionFactory;
     public NHibernateRepo(SessionFactory sessionFactory)
     {
       _sessionFactory = sessionFactory;
     }

     public IQueryable<TEntity> Find()
     {
        ISession session = _sessionFactory.OpenSession();
        return session.Query<TEntity>();
     }

     public void Add(TEntity entity)
     {
         using (ISession session = _sessionFactory.OpenSession())
         {
             session.Save(entity);
         }
     }

      //Update and delete methods essentially same as add
}

这个会话管理似乎达到了我的需要,但我确信它一定有一些不安全的地方。有什么想法吗??

public class NHibernateRepo<TEntity> : IRepo<TEntity> where TEntity : class
{
    private readonly ISessionFactory _sessionFactory;
    private ISession _session;

    public NHibernateRepo(Configuration configuration)
    {
        configuration.SetProperty("current_session_context_class", "thread_static");
        _sessionFactory = configuration.BuildSessionFactory();
    }

    private ISession GetOpenSession()
    {
        if (_session == null)
        {
            if (!CurrentSessionContext.HasBind(_sessionFactory))
                CurrentSessionContext.Bind(_sessionFactory.OpenSession());

            _session = _sessionFactory.GetCurrentSession();
        }

        if (!_session.IsOpen)
        {
            _session = _sessionFactory.OpenSession();
        }

        return _session;
    }

    public IQueryable<TEntity> Find()
    {
        ISession session = GetOpenSession();
        session.Clear();

        return session.Query<TEntity>();
    } 

    public void Update(TEntity value)
    {
        using (ISession session = GetOpenSession())
        {
            session.Transaction.Begin();
            session.Update(value);
            session.Transaction.Commit();

            session.Flush();
            session.Clear();
        }
    }

【问题讨论】:

  • 问题不在于您的存储库,而在于您的会话管理。您是否根据请求打开闭幕会议? (这是一个网络项目吗)
  • 它是一个 Windows Server\Win 窗体客户端项目,但理想情况下,我想在任何项目类型中使用相同的存储库样式。我将在我的问题上附上整个 Repo 课程。我对 Nhibernate 会话管理不太了解。

标签: c# session nhibernate memory-leaks dispose


【解决方案1】:

您需要做的是在您的代码中添加适当的会话管理,nHibernate 无法猜测您何时完成并处置您的会话。一种标准方法是使用 using 语句嵌入您的操作

public void SomeMethod()
{
     using(var session = _sessionFactory.OpenSession(_session))
     {
         var repository = new NHibernateRepo<MyType>();
         var list = repository.MyEntity.Find().Where(e => e.Id ==0).First();
     } //here everything is disposed
}

当然,以标准方式,您会将会话对象包装在其他东西中,通常是 UnitOfWork 或类似的,但重点是您需要处理会话:

  • 请求开始时打开一次
  • 在请求期间处理它
  • 最后丢弃
  • 如有异常请处理

所以一个真正的异常处理代码看起来更像

public void SomeMethod()
{
     using(var repository = new NHibernateRepo<MyType>(_sessionFactory))
     {
         var list = repository .MyEntity.Find().Where(e => e.Id ==0).First();
     }
}

public class NHibernateRepo<TEntity> : IDisposable{
    private ISession _session;


   public NHibernateRepo(ISessionFactory sessionFactory) { 
          _session = sessionFactory.OpenSession();
    }

   public IQueryable<TEntity> Find(){

        try{
            return session.Query<TEntity>();
        }
        catch(Exception ex){
             //session clear / close 
             // transaction rollbacks etc.
        }
   }

   public void Dispose(){
     //here goes session close stuff etc.
   }
}

【讨论】:

  • 我明白了,所以我必须在调用方法中更新 repo。理想情况下,我宁愿将 repo 作为 IRepo 注入到一个类中,而不是暴露 NHibernate。类似public class MyRepoUsingClass(IRepo repo)
  • 我在 NHibernateRepo 类中添加了一些会话管理。它似乎达到了我所需要的,但是我担心我的课程只有一节课,这样可以吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-08
  • 2013-01-20
  • 2011-10-31
  • 2019-08-10
  • 2013-06-24
  • 2011-03-22
相关资源
最近更新 更多