0

Я хочу перенести свою Единицу работы в сторону от моей бизнес-логики.Единица работы в общем хранилище

В Infrastructure.Data У меня есть

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 
} 

В Intrastructure.DependencyInjectrion у меня есть:

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<>)); 

    } 

Тогда в моей службы я хотел бы сделать что-то вроде этого:

Web.UI.Services.CompanyService

public void CreateNewCompany (Company company) 
    { 
     if (_companyRepository.Add (company)) 
      _unitOfWork.Commit(); 
     else 
      _unitOfWork.Rollback(); 
    } 

было бы лучше перевести _unitOfWork.Commit() или _unitOfWork.Rollback() в eneric Repository, а не в слой Service?

Я думал об улучшении общего Repository, введя в него IUnitOfWork, добавив также дополнительную обработку ошибок.

Если это нехороший подход, может ли кто-нибудь дать мне некоторое направление, чтобы улучшить это? Примечание. Я хочу сохранить repository pattern в случае, если мы захотим переключить ORM через несколько лет.

ответ

1

Управление транзакциями в репозитории определенно не является стандартным способом его выполнения, поскольку он устраняет возможность реализации бизнес-логики, которая охватывает несколько репозиториев (или несколько действий в одном и том же репозитории) и должна выполняться атомарно.

Я бы попытался сохранить управление транзакциями на самом верхнем слое, что имеет смысл, т. Е. Не ухудшает вашу способность повторно использовать бизнес-логику (включая управление транзакциями), если вы решили разместить свое приложение в другом среды, например. Это, по-видимому, будет уровнем обслуживания в вашем случае; вы также можете различать различные виды услуг, как это сделано в Domain-Driven Design, где существует разница между прикладными службами и услуг домена. Службы приложений могут организовать несколько доменных служб и обрабатывать управление транзакциями и потенциально единицу работы).

Надеюсь, это поможет.

+0

Этот вид имеет смысл. Не могли бы вы сказать, что способ выполнения единицы работы в настоящий момент хорош? и просто оставить это как есть? Я пойду прочитаю немного больше DDD, Думаю, я пропустил что-то haha ​​ –

+0

Я бы сказал, что реализация Unit of Work выглядит в целом прекрасной для меня.Я полагаю, что экземпляр создается на единицу работы (независимо от того, что может быть, возможно, HTTP-запрос). Единственное, о чем вы могли бы подумать, заключается в том, хотите ли вы реализовать финализатор, который распределяет единицу работы, и хотите ли вы проверить активные транзакции в распоряжении (если есть активная транзакция, выполнить откат и зарегистрировать ошибку или что-то еще , это предотвратит открытые транзакции - не уверен, что 'Session.Close()' позаботится об этом уже). – PermaFrost

+0

Кроме того, я лично использовал бы подразделение работы немного по-другому, я бы не откатил транзакцию, если бы мог быть уверен, что ничего не изменилось, как это сделано в приведенном вами служебном коде. Обязательства всегда дешевле, чем откаты на РСУБД. – PermaFrost