使用存储库模式构建单页应用程序但没有工作单元 - SaveChanges在哪里?

时间:2013-03-03 21:26:44

标签: c# asp.net asp.net-mvc design-patterns asp.net-web-api

我正在阅读Repository和UOW模式,看起来UOW需要一堆数据,在内存中对数据进行修改,然后在某个时刻提交更改。如果我没有拥有,我不想实现另一个图层,所以我试图将一些UOW职责委托给我的存储库(即保存)。

我当前应用程序的存储库立即执行保存,如下所示:

public void DeleteBox(int BoxId)
        {
            var Box = GetBox(BoxId);
            if (Box != null)
            {
                foreach (var subBox in Box.Boxes.ToList())
                {
                    DeleteBox(subBox.BoxId);
                }

                if (Box.ParentBox != null)
                {
                    Box.ParentBox.Boxs.Remove(Box);
                    _db.SaveChanges();
                }
                _db.Boxs.Remove(Box);
                _db.SaveChanges();
            }
            else throw new InvalidOperationException("Cannot delete Box because it doesn't exist");
        }

目前的代码"工作"但是我想知道在这里执行SaveChanges是不是很理想。在我开始构建WebAPI时,我是否应该考虑从控制器操作调用saveChanges,并修改存储库中应用程序的状态?任何文章或参考文献都可以帮助我更好地理解应该如何进行储蓄会很棒 - 我现在有点不知所措。

1 个答案:

答案 0 :(得分:2)

就个人而言,我喜欢创建一个完整的存储库类来处理域模型对象的所有CRUD操作,并通过接口将此存储库传递给MVC控制器。然后,控制器根据应用程序逻辑在存储库上运行各种方法。

我觉得这种方法有两个主要优点:

  1. 您可以清楚地分离存储库中的数据访问代码和控制器中的应用程序逻辑代码。因此,您的存储库完全负责数据访问,并且您的控制器维护应用程序逻辑。
  2. 这是构建测试内容的有效方法。通过接口将存储库传递到控制器,您可以通过模拟框架(如RhinoMocks或Moq)完全控制您的控制器。您的数据访问代码很难或无法有效测试,它集中在一个不可测试的类中。
  3. 例如,假设我想让一个控制器对Product类进行完整的CRUD操作。我将创建一个存储库接口和实现,如下所示。请注意,存储库实现需要对象关系映射器(ORM)或数据访问层的实例。在这个例子中,我通过构造函数中的ISession接口传入nHibernate Session对象的实例。

    public interface IProductRepo
    {
        List<Product> GetProducts();
        Product GetProduct(int Id);
        void DeleteProduct(int Id);
        void CreateProduct(Product product);
        void UpdateProduct(Product product);
    }
    
    public class ProductRepo : IProductRepo
    {
        public ProductRepo(ISession session)
        {
             _session = session;  
        }
    
        public Product GetProduct(int Id)
        {
             return _session<Product>().Get(Id);
        }
    
        //Implementation of other methods of IProductRepo
    
         ISession _session;
    }
    

    然后可以通过构造函数注入(我最喜欢的)或属性注入将此repo传递给控制器​​。所以你的控制器看起来像这样:

    public class ProductController : ApiController
    {
        public ProductController(IProductRepo repo)
        {
            _repo = repo;
        }
        public List<Product> GetProducts()
        {
            //other code as needed
            return _repo.GetProducts();
        }
        public Product GetProduct(int id)
        {
            //other code as needed
            return _repo.GetProduct(id);
        }
        public void PostProduct(Product product)
        {
            _repo.CreateProduct(product);
            //other code as needed
        }
        public void PutProduct(Product product)
        {
            _repo.UpdateProduct(product);
            //other code as needed
        }
        public void DeleteProduct(int id)
        {
            _repo.DeleteProduct(id);
            //other code as needed
        }
    }
    

    Microsoft有一个good article,它为Web API提供了一个基本的例子。

    编辑:存储库模式

    Martin Fowler

    的话说
      

    存储库在域和数据映射层之间进行调解,其作用类似于内存中的域对象集合。

    它通常与对象关系映射器(ORM)或数据访问层结合使用,如nHibernate或Entity Framework。因此,您的存储库将采用ORM或数据访问类的实例,实际执行写入和读取持久层。存储库用于封装ORM /数据访问类的所有查询和CRUD操作。