这是一个很好的UnitOfWork与DDD的存储库模式设计

时间:2012-02-17 12:59:20

标签: c# asp.net-mvc domain-driven-design repository-pattern unit-of-work

我正在使用UOW和Repository模式构建一个Web应用程序。我对此有一个基本的了解,我想知道我是否应该为我的项目中的所有表保留一个UOW实现,或者根据功能保留一个单独的实现,例如:

public interface IHomeUOW
{
    IGenericRepository<User> Users { get; }
    IGenericRepository<TableA> Table_A { get; }
    IGenericRepository<TableB> Table_B{ get; }
}

public interface IBusinessCaseUOW
{

    IGenericRepository<TableA> Table_A { get; }
    IGenericRepository<TableXYZ> Table_XYZ{ get; }
}

如您所见,TableA既可用于Home UOW,也可用于特定的商业案例UOW。一个UOW部分实现如下:

public class UnitOfWork : IUnitOfWork
{

    private readonly ObjectContext _context;
    private UserRepository _userRepository;


    public UnitOfWork(ObjectContext Context)
    {

        if (Context == null)
        {
            throw new ArgumentNullException("Context wasn't supplied");
        }
        _context = Context;
    }

    public IGenericRepository<User> Users
    {
        get
        {
            if (_userRepository == null)
            {
                _userRepository = new UserRepository(_context);
            }

            return _userRepository;
        }
    }
 }

我的存储库就像这样

    public interface IGenericRepository<T>
    where T : class
    {
        //Fetch records
        T GetSingleByRowIdentifier(int id);             
        T GetSingleByRowIdentifier(string id);          

        IQueryable<T> FindByFilter(Expression<Func<T, bool>> filter);  

        // CRUD Ops
        void AddRow(T entity);
        void UpdateRow(T entity);
        void DeleteRow(T entity);

    }


    public abstract class GenericRepository<T> : IGenericRepository<T>
            where T : class
    {
        protected IObjectSet<T> _objectSet;
        protected ObjectContext _context;

        public GenericRepository(ObjectContext Context)
        {
            _objectSet = Context.CreateObjectSet<T>();
            _context = Context;
        }

        //Fetch Data
        public abstract T GetSingleByRowIdentifier(int id);
        public abstract T GetSingleByRowIdentifier(string id);


        public IQueryable<T> FindByFilter(Expression<Func<T, bool>> filter)
        {
            //
        }

        //CRUD Operations implemented

    }

   public class UserRepository : GenericRepository<User>
   {
         public UserRepository(ObjectContext Context)
         : base(Context)
         {
         }

         public override User GetSingleByRowIdentifier(int id)
         {
          //implementation
         }

         public override User GetSingleByRowIdentifier(string username)
         {
          //implementation
         }
   }
你怎么看?如果这不是DDD的UOW和Repository模式的正确实现,它会失败,因为只是编写一堆代码来抽象调用EF表吗?

谢谢你的时间..

2 个答案:

答案 0 :(得分:5)

我对通用存储库过敏。每次我使用一个我必须做的解决开放/封闭原则的解决方法。

我建议您切换到根聚合特定存储库并在其中使用OR / M.

工作单位。 EF和nhibernate已经实现了模式。只需创建一个界面,如:

public interface IUnitOfWork : IDisposable
{
    void SaveChanges();
}

不保存处置=回滚。

nhibernate实现看起来像(快速写入,未经过测试):

public class NHibernateUnitOfWork : IDisposable
{
    public NHibernateUnitOfWork(ISession session)
    {
        _transaction = session.BeginTransaction();
    }

    public void SaveChanges()
    {
        _transaction.Commit();
    }

    public void Dispose()
    { 
        _transaction.Dispose();
    }
}

使用IoC容器非常简单。只需在其中注册实现。

我最喜欢在ASP.NET MVC中获得事务支持的解决方案是创建一个名为ActionFilter的自定义TransactionalAttribute并让它处理UnitOfWork实现:

[HttpPost, Transactional]
public ActionResult Update(YourModel model)
{
}

我刚刚将答案转换为更详细的博文:http://blog.gauffin.org/2012/02/repositories-unit-of-work-and-asp-net-mvc/

答案 1 :(得分:1)

我认为这是错误的。

UnitOfWork是Transaction(简单来说)。它至少应包含一个方法Complete(Commit)。

如果你使用EntityFramework你包装ObjectContext,如果你使用纯ADO .NET你包装TransactionScope,如果使用NHibernate ISession等。

这是我的UOF:

public interface IUnitOfWork : IDisposable
{
    void Complete();
    TRepository GetRepository<TRepository, TItem>()
        where TRepository : IRepository<TItem>
        where TItem : class;
}