使用工作单元和存储库

时间:2016-03-12 11:49:58

标签: asp.net-mvc entity-framework repository domain-driven-design unit-of-work

我正在尝试在我的项目中使用工作单元和存储库。 然后让我思考如何用它实现交易。

目前这是我打算做的事情:

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

我现在真的很困惑应该如何实现工作单元和存储库,因为据我所知,工作单元将成为所有存储库访问权限的主要门。

如果有人能够对这个工作单元和存储库实现有所了解,我将非常感激。

非常感谢你。

3 个答案:

答案 0 :(得分:3)

UnitOfWork应该开始并完成交易。这直接源于其名称。

我在原始代码中会改变的是,您的UoW知道太多的存储库。如果再添加一个存储库,则必须更改UoW类,这是一件坏事。

您需要将UoW实例注入通用存储库构造函数,并使用存储库中的UoW上下文。

使用IoC容器时,您需要确保您的存储库和UoW具有匹配的生命周期范围。

答案 1 :(得分:1)

应该只在您的工作单元类中创建并将相同的 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>();          
    }

答案 2 :(得分:0)

感谢Alexey和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;
        }
    }
}

我在实例化存储库时采用了工作单元,如下所示:

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方法添加到其中,因此它可以保存(对于我需要新插入的实体的情况)但是仍然在事务中包装。

谢谢