0

Я пытаюсь использовать единицу работы и хранилище в своем проекте. Который тогда заставлял меня думать о том, как реализовать транзакцию с ним.Использование единицы работы и репозитория

На данный момент это то, что я планирую сделать:

public class UnitOfWork : IUnitOfWork 
{ 

    private readonly IDbFactory databaseFactory; 
    private adminBoContext dataContext; 
    private DbContextTransaction _transaction; 

    private Repository<a> repoA; 
    .... 
    private Repository<x> repoX; 

    public UnitOfWork(IDbFactory databaseFactory) 
    { 
     this.databaseFactory = databaseFactory; 
     _transaction = dataContext.Database.BeginTransaction(); 
    } 

    protected Context DataContext 
    { 
     get { return dataContext ?? (dataContext = databaseFactory.Get()); } 
    } 

    public void Commit() 
    { 
     try 
     { 
      _transaction.Commit(); 
     } 
     catch (Exception ex) 
     { 
      _transaction.Rollback(); 
     } 
    } 
} 

но потом я наткнулся, например, такие, как SocialGoal project где она имеет Единица работы (но без хранилищ внутри него) и отдельных хранилищ, похоже, имеет свой собственный экземпляр контекста

public class UnitOfWork : IUnitOfWork 
{ 
    private readonly IDatabaseFactory databaseFactory; 
    private SocialGoalEntities dataContext; 

    public UnitOfWork(IDatabaseFactory databaseFactory) 
    { 
     this.databaseFactory = databaseFactory; 
    } 

    protected SocialGoalEntities DataContext 
    { 
     get { return dataContext ?? (dataContext = databaseFactory.Get()); } 
    } 

    public void Commit() 
    { 
     DataContext.Commit(); 
    } 
} 

public abstract class RepositoryBase<T> where T : class 
{ 
    private SocialGoalEntities dataContext; 
    private readonly IDbSet<T> dbset; 
    protected RepositoryBase(IDatabaseFactory databaseFactory) 
    { 
     DatabaseFactory = databaseFactory; 
     dbset = DataContext.Set<T>(); 
    } 

    protected IDatabaseFactory DatabaseFactory 
    { 
     get; 
     private set; 
    } 

    protected SocialGoalEntities DataContext 
    { 
     get { return dataContext ?? (dataContext = DatabaseFactory.Get()); } 
    } 
    public virtual void Add(T entity) 
    { 
     dbset.Add(entity); 
    } 

Я действительно путают теперь в том, как на самом деле единицы работы и хранилища должны быть реализованы, потому что, как я понимаю, что единица работы будет вид главных ворот КН ich будет проходить весь доступ к хранилищам.

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

Большое вам спасибо.

ответ

1

The DataContext должны быть созданы только в вашей единице работы класса и передать те же DataContext в хранилищах, что DataContext также должны быть совершены или откат в вашей единице работы.

Ваши репозитории не должны создавать свой собственный dataContext, но использовать переданные в dataContext из Единицы работы. При этом мы можем координировать транзакцию между репозиториями.

Пример код из вашего вопроса может быть реализован следующим образом:

public class UnitOfWork : IUnitOfWork 
{ 

    private readonly IDbFactory databaseFactory; 
    private adminBoContext dataContext; 
    private DbContextTransaction _transaction; 

    private Repository<a> repoA; 
    private Repository<x> repoX; 

    public UnitOfWork(IDbFactory databaseFactory) 
    { 
     this.databaseFactory = databaseFactory; 
     _transaction = DataContext.Database.BeginTransaction(); 

     //pass the same context to your repositories 
     repoA = new Repository<A>(DataContext); 
     repoX = new Repository<X>(DataContext); 
    } 

    protected Context DataContext 
    { 
     get { return dataContext ?? (dataContext = databaseFactory.Get()); } 
    } 

    public void Commit() 
    { 
     try 
     { 
      _transaction.Commit(); 
     } 
     catch (Exception ex) 
     { 
      _transaction.Rollback(); 
     } 
    } 
} 

Примечание стороны:

ФАКС работы должны осуществлять IDisposable, чтобы гарантировать, что контекст всегда располагаются даже тогда, когда мы забываем делать это явно. Реализовать еще немного кода, как это:

private bool disposed = false; 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!this.disposed) 
     { 
      if (disposing) 
      { 
       dataContext.Dispose(); 
      } 
     } 
     this.disposed = true; 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

Ваш код должен выглядеть примерно так:

public class UnitOfWork : IUnitOfWork, IDisposable 
    { 

     private readonly IDbFactory databaseFactory; 
     private adminBoContext dataContext; 
     private DbContextTransaction _transaction; 

     private Repository<a> repoA; 
     private Repository<x> repoX; 

     public UnitOfWork(IDbFactory databaseFactory) 
     { 
      this.databaseFactory = databaseFactory; 
      _transaction = DataContext.Database.BeginTransaction(); 

      //pass the same context to your repositories 
      repoA = new Repository<A>(DataContext); 
      repoX = new Repository<X>(DataContext); 
     } 

     protected Context DataContext 
     { 
      get { return dataContext ?? (dataContext = databaseFactory.Get()); } 
     } 

     public void Commit() 
     { 
      try 
      { 
       _transaction.Commit(); 
      } 
      catch (Exception ex) 
      { 
       _transaction.Rollback(); 
      } 
     } 

     private bool disposed = false; 

     protected virtual void Dispose(bool disposing) 
     { 
      if (!this.disposed) 
      { 
       if (disposing) 
       { 
        dataContext.Dispose(); 
       } 
      } 
      this.disposed = true; 
     } 

     public void Dispose() 
     { 
      Dispose(true); 
      GC.SuppressFinalize(this); 
     } 
    } 

Ваше хранилище:

public abstract class RepositoryBase<T> : IRepository<T> 
    where T : class 
{ 
    protected DbSet<T> Set { get; set; } 
    protected Context Context { get; private set; } 

    protected RepositoryBase(Context dataContext) 
    { 
     Context = dataContext; 
     Set = Context.Set<T>();   
    } 
3

UnitOfWork должны начать и завершить сделку. Это происходит непосредственно от его имени.

Что я изменил бы в вашем исходном коде, так это то, что ваш UoW знает слишком много ваших репозиториев. Если вы добавите еще один репозиторий, вы должны изменить свой класс UoW и это Bad Thing.

Вместо этого вы должны ввести свой экземпляр UoW в общий конструктор репозитория и использовать контекст UoW внутри репозитория.

При использовании контейнеров IoC вам необходимо убедиться, что у вас есть соответствующая область действия времени для ваших репозиториев и для UoW.

0

Спасибо Алексей и Khanh,

После ваше предложение, я пытаюсь изменить свою единицу работы, как показано ниже:

public class UnitOfWork : IUnitOfWork 
{ 
    private readonly IDbFactory databaseFactory; 
    private Context dataContext; 
    private DbContextTransaction _transaction; 

    public UnitOfWork(IDbFactory databaseFactory) 
    { 
     this.databaseFactory = databaseFactory; 

    } 

    public IDbContext BeginTransaction<T>() 
    { 
     if (_dataContext == null) 
     { 
      _dataContext = _databaseFactory.Get<T>(); 
      _transaction = _dataContext.BeginTransaction(); 
     } 

     return _dataContext; 
    } 

    public void Commit() 
    { 
     try 
     { 
      _transaction.Commit(); 
     } 
     catch (Exception ex) 
     { 
      _transaction.Rollback(); 
      throw ex; 
     } 
    } 
} 

и я беру единицу работы при Instantiate хранилище как следующим образом:

public abstract class RepositoryBase<T> : IRepository<T> 
    where T : class 
{ 
    protected DbSet<T> Set { get; set; } 
    protected Context Context { get; private set; } 

    protected RepositoryBase(IDbContext context) 
    { 
     Context = context; 
     Set = Context.Set<T>();    
    } 

    //CRUD functions 

    public void Save() 
    { 
     Context.SaveChanges(); 
    } 
} 

@Alexey, это то, что вы подразумеваете под инъекцией UOW в хранилище?

@Khanh, теперь я передаю контекст непосредственно в репозиторий и добавляю в него метод Save, поэтому он может сохранять (для случая, когда мне нужен только что вставленный объект), но затем все же переносить внутри транзакции.

Спасибо

+0

Ознакомьтесь с моим обновленным сообщением. Лично мне не нравится передавать всю единицу работы в репозиторий, мы должны передать «только то, что необходимо», которое является DataContext. Надеюсь, поможет. –

+0

Thanks Khanh, Я редактирую свой код выше, передавая непосредственно контекст в репозиторий, а также добавляю для него метод сохранения. – hollycrab

+0

вы не должны вызывать сохранение внутри репозитория, пусть это сделает блок работы. Вот почему это называется единицей работы (даже эта единица работы имеет только 1 операцию) –