I want to move my Unit of work away from my business logic.
In Infrastructure.Data
I have
NHibernateHelper
public class NHibernateHelper
{
private ISessionFactory _sessionFactory;
private readonly string _connectionString;
public NHibernateHelper (string connectionString)
{
if (string.IsNullOrEmpty (connectionString))
throw new HibernateConfigException ("ConnectionString in Web.config is not set.");
_connectionString = connectionString;
}
public ISessionFactory SessionFactory {
get {
return _sessionFactory ?? (_sessionFactory = InitializeSessionFactory ());
}
}
private ISessionFactory InitializeSessionFactory ()
{
return Fluently.Configure ()
.Database (PostgreSQLConfiguration.Standard.ConnectionString (_connectionString).
Dialect ("NHibernate.Dialect.PostgreSQL82Dialect"))
// Use class mappings
.Mappings (m => m.FluentMappings.AddFromAssembly (Assembly.GetExecutingAssembly ()))
// Will Update and create tables if does not exist
.ExposeConfiguration (cfg => new SchemaUpdate (cfg).Execute (true, true))
.BuildSessionFactory ();
}
}
UnitOfWork
public class UnitOfWork : IUnitOfWork
{
private readonly ISessionFactory _sessionFactory;
private readonly ITransaction _transaction;
public ISession Session { get; private set; }
public UnitOfWork (ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
Session = _sessionFactory.OpenSession ();
Session.FlushMode = FlushMode.Auto;
_transaction = Session.BeginTransaction (IsolationLevel.ReadCommitted);
}
public void Commit ()
{
if (!_transaction.IsActive) {
throw new InvalidOperationException ("Oops! We don't have an active transaction");
}
_transaction.Commit ();
}
public void Rollback ()
{
if (_transaction.IsActive) {
_transaction.Rollback ();
}
}
public void Dispose ()
{
if (Session.IsOpen) {
Session.Close ();
Session = null;
}
}
}
Repository
public class Repository<TEntity> : IReadWriteRepository<TEntity>
where TEntity : class
{
private readonly ISession _session;
public Repository (ISession session)
{
_session = session;
}
#region IWriteRepository
public bool Add (TEntity entity)
{
_session.Save (entity);
return true;
}
public bool Add (System.Collections.Generic.IEnumerable<TEntity> entities)
{
foreach (TEntity entity in entities) {
_session.Save (entity);
}
return true;
}
public bool Update (TEntity entity)
{
_session.Update (entity);
return true;
}
public bool Update (System.Collections.Generic.IEnumerable<TEntity> entities)
{
foreach (TEntity entity in entities) {
_session.Update (entity);
}
return true;
}
public bool Delete (TEntity entity)
{
_session.Delete (entity);
return true;
}
public bool Delete (System.Collections.Generic.IEnumerable<TEntity> entities)
{
foreach (TEntity entity in entities) {
_session.Delete (entity);
}
return true;
}
#endregion
#region IReadRepository
public System.Linq.IQueryable<TEntity> All ()
{
return _session.Query<TEntity> ();
}
public TEntity FindBy (System.Linq.Expressions.Expression<System.Func<TEntity, bool>> expression)
{
return FilterBy (expression).SingleOrDefault ();
}
public TEntity FindBy (object id)
{
return _session.Get<TEntity> (id);
}
public System.Linq.IQueryable<TEntity> FilterBy (System.Linq.Expressions.Expression<System.Func<TEntity, bool>> expression)
{
return All ().Where (expression).AsQueryable ();
}
#endregion
}
In Intrastructure.DependencyInjectrion
I have:
public void RegisterServices (SimpleInjector.Container container)
{
var connectionSettings = ConfigurationManager.ConnectionStrings ["Connection"];
container.RegisterPerWebRequest<ISessionFactory> (() => {
NHibernateHelper objNHibernate = new NHibernateHelper (connectionSettings.ConnectionString);
return objNHibernate.SessionFactory;
});
container.RegisterPerWebRequest<IUnitOfWork, UnitOfWork> ();
container.RegisterPerWebRequest<ISession> (() => {
UnitOfWork unitOfWork = (UnitOfWork)container.GetInstance<IUnitOfWork> ();
return unitOfWork.Session;
});
container.RegisterOpenGeneric (typeof(IReadWriteRepository<>), typeof(Repository<>));
}
Then in my service I would do something like this:
Web.UI.Services.CompanyService
public void CreateNewCompany (Company company)
{
if (_companyRepository.Add (company))
_unitOfWork.Commit ();
else
_unitOfWork.Rollback ();
}
Would it be a better practice to call _unitOfWork.Commit()
or _unitOfWork.Rollback()
in the eneric Repository
rather than in the in the Service
layer?
I was thinking of improving the generic Repository
by injecting the IUnitOfWork
into it while adding some additional error handling in too.
If this is not a good approach, can someone give me some direction to improve this? Note: I do want to keep repository pattern
in case we choose to switch ORM
in a few years time.