为什么我要将UnitOfWork与Repository Pattern一起使用?

时间:2012-01-02 17:47:10

标签: asp.net entity-framework-4.1 ioc-container repository-pattern unit-of-work

我在网上看到了很多关于UnitOfWork和Repo Pattern的内容,但仍然没有清楚地了解为什么以及何时使用 - 这对我来说有点混乱。

考虑到我可以通过使用DI来使我的存储库可测试,如本文What are best practices for managing DataContext中所建议的那样使用IoC。我正在考虑将上下文作为对我的存储库构造函数的依赖进行传递,然后像这样处理它?:

public interface ICustomObjectContext : IDisposable {}
public IRepository<T> // Not sure if I need to reference IDisposable here
public IMyRepository : IRepository<MyRepository> {}

public class MyRepository : IMyRepository
{
    private readonly ICustomObjectContext _customObjectContext;

    public MyRepository(ICustomObjectContext customObjectContext)
    {
        _customObjectContext = customObjectContext;
    }

    public void Dispose()
    {
        if (_customObjectContext != null)
        {
            _customObjectContext.Dispose();
        }
    }

    ...

}

我目前对使用UnitOfWork和Repository Pattern的理解是在多个存储库中执行操作 - 这种行为似乎与@Ladislav Mrnka为Web应用程序推荐的内容相矛盾:

  

对于Web应用程序,每个请求使用单个上下文。对于Web服务,每次调用使用单个上下文。在WinForms或WPF应用程序中,每个表单或每个演示者使用单个上下文。可能有一些特殊要求不允许使用这种方法,但在大多数情况下这已经足够了。

查看完整的答案here

如果我理解正确的话,DataContext应该是短暂的,并且可以在每个请求或演示者的基础上使用(在其他帖子中也可以看到)。在这种情况下,repo对上下文执行操作是合适的,因为范围仅限于使用它的组件 - 对吗?

我的回购在IoC中注册为瞬态,因此我应该为每个请求添加一个新的回购。如果这是正确的,那么我应该为每个请求获取一个新的上下文(上面的代码),然后处理它 - 说... 为什么我会使用具有存储库模式的UnitOfWork模式如果我遵循上述惯例?

3 个答案:

答案 0 :(得分:6)

据我所知,工作单元模式不一定涵盖多个上下文。它只是封装了一个操作或 - 井 - 工作单元,类似于事务。

创建你的上下文基本上开始了一个工作单元;调用DbContext.SaveChanges()完成它。

我甚至可以说,在其当前实现中,实体框架的DbContext / ObjectContext类似于存储库模式和工作单元模式。

答案 1 :(得分:3)

如果我想在一个Web请求中共享相同的上下文实例时,我想使用简化的UoW将上下文的SaveChanges从存储库中推出。

我想你的存储库上的Save()方法看起来与_customObjectContext.SaveChanges()类似。现在假设您有两个包含业务逻辑的方法,并使用repos来持久保存DB中的更改。为了简单起见,我们将其称为MethodAMethodB,它们都包含用于执行某些活动的大量逻辑。 MethodA在系统中单独使用,但由于某种原因由MethodB调用。会发生什么情况MethodA会保存对某些存储库的更改,因为我们仍然处于相同的请求中,MethodB在调用MethodA之前所做的更改也将被保存,无论我们是否需要它或不。因此,在这种情况下,我们无意中破坏了MethodB内的事务,并使代码更难理解。

我希望我对此描述得足够清楚,这并不容易。无论如何,除此之外,我无法理解为什么UoW会对您的场景有所帮助。正如Dennis Traub指出的那样,ObjectContext和DbContext实际上是一个UoW的实现,所以你可能会在自己实现它时重新发明轮子。

答案 2 :(得分:1)

ObjectContext/DbContext是UnitOfWork模式的实现。它封装了几个操作,并确保它们在一个事务中提交到数据库。

您唯一要做的就是将它包装在您自己的类中,以确保您不依赖于其余代码中的特定实现。

在您的情况下,问题在于您的Context不应由Repository处理。 Repository不是实例化Context的那个,所以它也不应该处理它。封装多个存储库的UnitOfWork负责创建和部署Context,您将在Save上调用UnitOfWork方法。

代码可以如下所示:

using (IUnitOfWork unitOfWork = new UnitOfWork())
{
   PersonRepository personRepository = new PersonRepository(unitOfWork);
   var person = personRepository.FindById(personId);

   ProductRepository productRepository = new ProductRepository(unitOfWork);
   var product= productRepository.FindById(productId);

   p.CreateOrder(orderId, product);
   personRepository.Save();
}
相关问题