Reputation: 1267
I've been using a generic Repository along with NHibernate, but I am having a problem in stopping memory leaks/leaving sessions open.
The method is
public IQueryable<TEntity> Find()
{
ISession session = _sessionFactory.OpenSession();
return session.Query<TEntity>();
}
Obviously this leaves the session open, however when I use the follwing
public IQueryable<TEntity> Find()
{
using (ISession session = _sessionFactory.OpenSession())
{
return session.Query<TEntity>();
}
}
The session is closed when the query is run.
Is there anyway I can dispose of the session after the query has run??
The calling of this method looks like this:
MyRepo repo = new MyRepo();
var list = repo.MyEntity.Find().Where(e => e.Id ==0).First();
//Need to dispose here????
Can this be done without the calling method needing to explicity dispose. I.e. I would like to avoid.
MyRepo repo = new MyRepo();
var list = repo.MyEntity.Find().Where(e => e.Id ==0).First();
repo.DisposeSession();
Thanks in advance.
EDIT
Here is the repo class
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
}
This session management seems to achieve what I need, however I am sure there must be something unsafe about it. Any thoughts??
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();
}
}
Upvotes: 0
Views: 2046
Reputation: 2468
What you need to do is to add proper session management to your code , nHibernate can't guess when you're done and dispose your session. A standard way would be to embedd your actions with using statement
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
}
Of course in standard way you would wrap the session object inside something else , usually UnitOfWork or similar but the point is that you need to handle session and :
So a real code with exception handling will rather look like
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.
}
}
Upvotes: 1