为什么我想将 UnitOfWork 与存储库模式一起使用?

发布于 2024-12-24 17:29:58 字数 1590 浏览 2 评论 0原文

我在网上看到了很多关于 UnitOfWork 和 Repo 模式的信息,但仍然不清楚为什么以及何时使用——这让我有些困惑。

考虑到我可以通过使用 DI 通过使用 IoC 来测试我的存储库,如本文中所建议的 管理 DataContext 的最佳实践是什么。我正在考虑将上下文作为对我的存储库构造函数的依赖项传递

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 与存储库模式的理解是跨多个存储库执行操作 - 这种行为似乎与 @ Ladislav Mrnka 对 Web 应用程序的建议:

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

请参阅完整答案此处

如果我正确理解他,DataContext 应该是寿命很短,并根据每个请求或演示者使用(在其他帖子中也看到了这一点)。在这种情况下,存储库针对上下文执行操作是合适的,因为范围仅限于使用它的组件 - 对吗?

我的存储库在 IoC 中注册为临时存储库,因此我应该针对每个请求获取一个新的存储库。如果这是正确的,那么我应该为每个请求获取一个新的上下文(上面的代码),然后处理它——也就是说......为什么我要使用 UnitOfWork 模式和存储库模式,如果我遵循上述约定吗?

I've seen a lot about UnitOfWork and Repo Pattern on the web but still don't have a clear understanding of why and when to use -- its somewhat confusing to me.

Considering I can make my repositories testable by using DI thru the use of an IoC as suggested in this post What are best practices for managing DataContext. I'm considering passing in a context as a dependency on my repository constructor then disposing of it like so?:

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

    ...

}

My current understanding of using UnitOfWork with Repository Pattern, is to perform an operation across multiple repositories -- this behavior seems to contradict what @Ladislav Mrnka recommends for web applications:

For web applications use single context per request. For web services use single context per call. In WinForms or WPF application use single context per form or per presenter. There can be some special requirements which will not allow to use this approach but in most situation this is enough.

See the full answer here

If I understand him correctly the DataContext should be shortlived and used on a per request or presenter basis (seen this in other posts as well). In this case it would be appropriate for the repo to perform operations against the context since the scope is limited to the component using it -- right?

My repos are registered in the IoC as transient, so I should get a new one with each request. If that's correct, then I should be getting a new context (with code above) with each request as well and then disposing of it -- that said...Why would I use the UnitOfWork Pattern with the Repository Pattern if I'm following the convention above?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

喜爱纠缠 2024-12-31 17:29:58

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

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

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

As far as I understand the Unit of Work pattern doesn't necessarily cover multiple contexts. It just encapsulates a single operation or -- well -- unit of work, similar to a transaction.

Creating your context basically starts a Unit of Work; calling DbContext.SaveChanges() finishes it.

I'd even go so far as to say that in its current implementation Entity Framework's DbContext / ObjectContext resembles both the repository pattern and the unit of work pattern.

软糖 2024-12-31 17:29:58

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

我想您的存储库上有类似 Save() 方法,看起来类似于 _customObjectContext.SaveChanges()。现在假设您有两种包含业务逻辑并使用存储库将更改保存在数据库中的方法。为了简单起见,我们将它们称为 MethodAMethodB,它们都包含大量用于执行某些活动的逻辑。 MethodA在系统中单独使用,但由于某种原因也被MethodB调用。发生的情况是 MethodA 将更改保存在某个存储库上,并且由于我们仍在 MethodB 中进行相同的请求更改,因此在调用 MethodA 之前,将无论我们愿意与否,也都得救。因此,在这种情况下,我们无意中破坏了 MethodB 内部的事务,并使代码更难以理解。

我希望我描述得足够清楚,这并不容易。除此之外,我不明白为什么 UoW 对您的情况有帮助。正如 Dennis Traub 非常正确地指出的那样,ObjectContext 和 DbContext 实际上是 UoW 的实现,因此您在自己实现它时可能会重新发明轮子。

I would use a simplified UoW if i wanted to push context's SaveChanges away from the repositories when they share the same instance of context across one web request.

I imagine you have sth like Save() method on your repositories that looks similiar to _customObjectContext.SaveChanges(). Now lets assume you have two methods containing business logic and using repos to persist changes in DB. For the sake of simplicity we'll call them MethodA and MethodB, both of them containing a fair amount of logic for performing some activities. MethodA is used separately in the system but also it is called by MethodB for some reason. What happens is MethodA saves changes on some repository and since we are still in the same request changes made in MethodB, before it called MethodA, will also be saved regardless of whether we want it or not. So in such case we unintentionally break the transaction inside MethodB and make the code harder to understand.

I hope i described this clear enough, it wasn't easy. Anyway other than that i cannot see why UoW would be helpful in your scenario. As Dennis Traub pointed quite correctly ObjectContext and DbContext are in fact an implementation of a UoW so you'd be probably reinventing the wheel while implementing it on your own.

冷清清 2024-12-31 17:29:58

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

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

就您而言,问题在于您的 Context 不应该由您的 Repository 处置。 Repository 不是实例化 Context 的对象,因此它也不应该丢弃它。封装多个存储库的 UnitOfWork 负责创建和处置 Context,您将在 UnitOfWork 上调用 Save 方法代码>.

代码可以如下所示:

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

The ObjectContext/DbContext is an implementation of the UnitOfWork pattern. It encapsulates several operations and makes sure they are submitted in one transaction to the database.

The only thing you are doing is wrapping it in your own class to make sure you're not depending on a specific implementation in the rest of your code.

In your case, the problem lies in the fact that your Context shouldn't be disposed of by your Repository. The Repository is not the one that instantiates the Context, so it shouldn't dispose of it either. The UnitOfWork that encapsulates multiple repositories is responsible for creating and disposing the Context and you will call a Save method on your UnitOfWork.

Code can look like this:

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();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文