【问题标题】:Is this a good UnitOfWork with Repository pattern Design around DDD这是一个很好的 UnitOfWork 与 DDD 周围的存储库模式设计吗
【发布时间】:2012-02-17 12:59:20
【问题描述】:

我正在使用 UOW 和存储库模式构建一个 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 表的调用而失败吗?

感谢您的宝贵时间..

【问题讨论】:

  • 这可能是new codereview stackexchange site 的候选帖子。这不是对 OP 的批评,因为他们可能还没有听说过。
  • 显然,OP has 听说过。重复的帖子。
  • 嗨,Kurt,实际上我在发完这篇文章后确实看到了另一个网站。现在它有了答案,我不能把它取下来。此外,这个网站似乎获得了更多点击,因为可能没有多少人知道另一个网站,这可以解释为什么那里的浏览量较少且没有答案。

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


【解决方案1】:

我对通用存储库过敏。每次我使用一个时,我都必须做一些破坏打开/关闭原则的变通方法。

我建议您切换到根聚合特定存储库并在其中使用您的 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/

【讨论】:

  • 根聚合:Order。聚合:OrderLine
  • 好的。在我的代码中,如果这不是 DDD 的 UOW 和存储库模式的正确实现,它是否会因为只是编写一堆代码来抽象对 EF 表的调用而失败?对不起,如果我听起来有点蹩脚。这是我第一次同时实现这两种模式并使用 MVC
  • DDD 是关于解决特定问题的。通用存储库试图解决通用问题。所以两人相处不来,恕我直言。在您的特定存储库中使用 EF 以充分利用其功能。
  • 谢谢。我正在努力解决这个问题。那么在您的博客示例中,MVC 更新操作方法将如何使用 UOW 类对表调用更新?.. 还是会使用 Repository 类?
  • 我的示例使用控制容器的反转来处理 UoW。
【解决方案2】:

我认为这是错误的。

UnitOfWork 是事务(简单来说)。它至少应该包含一个方法 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;
}

【讨论】:

  • 如果 Complete 没有被调用,我会在 Dispose 中回滚(就像 TransactionScope 一样)
  • 我已经向我的 UOW 添加了部分实现。我的实现基于这篇文章:codeproject.com/Articles/94782/…
  • @user20358 您提供的链接中的实现并不完美,但没关系,如果您不需要支持除 EF 之外的任何东西。我建议使用具体的存储库,例如 MyProductRepository : IRepository
  • 我目前只支持EF。所以这意味着我没有引入 UOW 模式?从我的代码中,我直接使用具体的存储库.. 正确吗?
  • @user20358,不完全是。 EF本身就是repository模式的实现,它的UOF叫做ObjectContext,它的repository叫做ObjectSet。如果您不打算使用除 EF 之外的任何东西,则不需要在其之上进行抽象。但创建一个是一种很好的方式(和实践)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-29
  • 1970-01-01
  • 1970-01-01
  • 2011-02-17
  • 1970-01-01
相关资源
最近更新 更多