Hi
Before I begin, I'd like to say that I have been using NHibernate for 1.5 years now. Previously, I am using the HibernateDaoSupport class provided in Spring.NET framework.
Now, I would like to write my own Generic Dao class that supply the generic typed CRUD operations for my database retrieval and manipulation needs.
But I am facing 2 main problems:
1. Session.
Get(id) returns Stale data. If
I update the data using SQL query in Query Analyzer, Session.Get(id) will not know about this update and therefore, obtain the data from its cache instead of hitting the database.
I've tried to open new session and close the session after each Get() is performed but it seems to choke if when the object contains a <many-to-one> association.
2. I'd like to know your opinions on my generic repository. Pls do correct & point me to the right light if you think that there are improvements that can be done:
Code:
public class GenericRepository<T, IdT> : Commons.Core.DataInterfaces.IRepository<T, IdT> where T : class
{
private ISessionFactory _sessionFactory;
private ISession _session;
public ISessionFactory SessionFactory
{
get { return _sessionFactory; }
set { _sessionFactory = value; }
}
public ISession Session
{
get
{
if (_session == null)
{
_session = SessionFactory.OpenSession();
}
else if(!_session.IsOpen)
{
_session = SessionFactory.OpenSession();
}
_session.CacheMode = CacheMode.Refresh;
return _session;
}
}
#region IRepository<T,IdT> Members
public virtual T Get(IdT id, Enums.LockMode lockMode)
{
return Session.Get<T>(id, ConvertFrom(lockMode));
}
public virtual IList<T> GetAll()
{
ICriteria criteria = Session.CreateCriteria(typeof(T));
return criteria.List<T>();
}
public virtual T Load(IdT id)
{
T t = Session.Get<T>(id);
Session.Refresh(t);
return t;
}
public virtual T Load(IdT id, Enums.LockMode lockMode)
{
return Session.Get<T>(id, ConvertFrom(lockMode));
}
public virtual IList<T> FindAll(T exampleInstance, params string[] propertiesToExclude)
{
ICriteria criteria = Session.CreateCriteria(typeof(T));
Example example = Example.Create(exampleInstance);
foreach (string propertyToExclude in propertiesToExclude)
{
example.ExcludeProperty(propertyToExclude);
}
criteria.Add(example);
return criteria.List<T>();
}
public virtual T FindOne(T exampleInstance, params string[] propertiesToExclude)
{
IList<T> foundList = FindAll(exampleInstance, propertiesToExclude);
if (foundList.Count > 1)
{
throw new NonUniqueResultException(foundList.Count);
}
else if (foundList.Count == 1)
{
return foundList[0];
}
return default(T);
}
public virtual T Save(T entity)
{
using (ITransaction tx = Session.BeginTransaction())
{
try
{
tx.Begin();
Session.Save(entity);
tx.Commit();
return entity;
}
catch (Exception exc)
{
tx.Rollback();
throw exc;
}
finally
{
Session.Close();
Session.Dispose();
_session = null;
}
}
}
public virtual T Update(T entity)
{
using (ITransaction tx = Session.BeginTransaction())
{
try
{
tx.Begin();
Session.Update(entity);
tx.Commit();
return entity;
}
catch (Exception exc)
{
tx.Rollback();
throw exc;
}
finally
{
Session.Close();
Session.Dispose();
_session = null;
}
}
}
public virtual T SaveOrUpdate(T entity)
{
using (ITransaction tx = Session.BeginTransaction())
{
try
{
tx.Begin();
Session.SaveOrUpdate(entity);
tx.Commit();
return entity;
}
catch (Exception exc)
{
tx.Rollback();
throw exc;
}
finally
{
Session.Close();
Session.Dispose();
_session = null;
}
}
}
public virtual void Evict(T entity)
{
Session.Evict(entity);
}
public void Delete(T entity)
{
using (ITransaction tx = Session.BeginTransaction())
{
try
{
tx.Begin();
Session.Delete(entity);
tx.Commit();
}
catch (Exception exc)
{
tx.Rollback();
throw exc;
}
finally
{
Session.Close();
Session.Dispose();
_session = null;
}
}
}
/// <summary>
/// Translates a domain layer lock mode into an NHibernate lock mode via reflection. This is
/// provided to facilitate developing the domain layer without a direct dependency on the
/// NHibernate assembly.
/// </summary>
private LockMode ConvertFrom(Enums.LockMode lockMode)
{
FieldInfo translatedLockMode = typeof(LockMode).GetField(lockMode.ToString(),
BindingFlags.Public | BindingFlags.Static);
return (LockMode)translatedLockMode.GetValue(null);
}
#endregion
}