2014-02-07 8 views
0

Я использую общий репозиторий вместе с NHibernate, но у меня проблема с остановкой утечек памяти/открытием сессий.NHibernate GenericRepo Memory Leak

Метод

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

Очевидно, что это оставляет сессию открытой, однако, когда я использую follwing

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???? 

Может ли это быть сделан без метода вызова нуждающегося в явной форме распоряжаться. То есть Хотелось бы избежать.

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

Заранее благодарен.

EDIT

Вот класс репо

управления
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(); 
     } 
    } 
+0

Проблема не с вашим хранилищем, а ваше управлением сеансами. Открываете ли вы закрытие сессии по запросу? (Это веб-проект) – Rippo

+0

Это клиентский проект Windows Server \ Win формы, но в идеале я хотел бы использовать тот же стиль репозитория в любом типе проекта. Я приложу весь класс Repo к моему вопросу. Я не слишком разбираюсь в управлении сеансами Nhibernate. –

ответ

0

Что вам нужно сделать, это добавить надлежащее управление сеансами в код NHibernate не может угадать, когда вы закончите и утилизовать сеанс. Стандартный путь будет возможность размещения ваших действий с помощью заявления

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 или подобный, но дело в том, что вам нужно работать с сессией и:

  • открыть его один раз, когда запрос начинается
  • ручки его при запросе
  • утилизировать в конце
  • выбрасывайте если есть exceptio п

Так реальный код с обработкой исключений будет скорее похож

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. 
    } 
} 
+0

Я вижу так, что мне придется обновлять репо в вызывающем методе. В идеале я предпочел бы вводить репо в класс как IRepo, чтобы не подвергать NHibernate. Что-то вроде 'public class MyRepoUsingClass (IRepo repo)' –

+0

Я добавил некоторое управление сеансом в класс NHibernateRepo.Кажется, я добился того, что мне нужно, но я беспокоюсь о том, что у меня есть одна сессия для класса, это хорошо? –