【问题标题】:How to configure Unit of Work如何配置工作单元
【发布时间】:2011-12-01 17:48:50
【问题描述】:

我正在取得进展,但仍在努力处理多层 MVC 应用程序中的工作单元。查看此处的示例:http://www.asp.net/entity-framework/tutorials/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application UoW 包装了所有存储库,并为每个存储库提供了相同 dbcontext 的副本。然后控制器可以使用类似的存储库:

var courses = unitOfWork.CourseRepository.Get(includeProperties: "Department");

现在假设您有一个访问存储库的服务层。您可以对其进行配置,使其依赖于 IUnitOfWork 实现,然后通过 Unity 传入 EfUnitOfWork 实现。然后,当服务完成某些任务时,它可以调用 unitOfWork.context.SaveChanges()。但是这种方法隐藏了服务的真正依赖关系;它需要的存储库。这也意味着测试服务需要您构建完整的 UoW。

所以我在想一定有一种不同的方法,我想知道以下方法之一或我上面提到的(或其他东西!)是否是正确的方法:

  • Service 接受相同的存储库参数和一个 IUnitOfWork。存储库与 Unity 提供的 dbContext 副本连接起来。 EfUnitOfWork 也连接到同一个副本。然后,服务可以像以前一样使用存储库,完成后使用 EfUnitOfWork 提交。
  • Service 只接收一个 IUnitOfWork,但通过将传入的 IUnitOfWork.dbcontext 的副本传递给它们来设置其所需的存储库

请帮忙!

詹姆斯

【问题讨论】:

  • 看看this blog post of mine,它向 IMO 展示了一个优雅的解决方案。
  • DbContext 一个工作单元,DbSet一个存储库。 I too have blogged about this,尽管我仍然需要再写一两篇文章来完成我的想法。我的解决方案的要点是尽可能重用生成的 EF 代码。最后,您创建了一个IUnitOfWork,即IDisposable,具有SaveChanges 方法,并公开IDbSet<TEntity> 属性。然后为你的DbContext创建一个部分类,并使其实现IUnitOfWork接口。
  • 可能必须稍微修改 T4 模板才能使部分类/接口的内容正常工作,并公开IDbSet<TEntity> 属性。最后,您的服务层将接受IUnitOfWork,有点像安德斯的回答,但它会在整个过程中使用接口而不是具体类(因此您不会直接公开DbContext)。这个解决方案可以被完全模拟/存根。
  • 感谢您的指导,这一切都帮助我了解了各种模式和工具。我认为现在我将坚持使用我在下面记录的解决方案,使用 DbContext 作为 UoW,使用 EF。
  • @Merlyn Morgan-Graham:你的博客不可用。你把它移到其他网站了吗?很好奇阅读它!

标签: asp.net-mvc asp.net-mvc-3 dependency-injection unit-of-work


【解决方案1】:

服务层通常设计为让每个方法执行一个完整的操作。服务层方法负责处理工作单元。使用这种方法,工作单元不应跨越对服务层的多次调用。

如果您想要一起进行更大的更新块,您可以使用事务。新建一个TransactionScope,然后在里面调用几个服务层方法:

using(TransactionScope ts = new TransactionScope())
{
  ServiceLayer.DoSomething();
  ServiceLayer.DoSomethingElse();
  ts.Commit();
}

【讨论】:

  • 我在服务中的方法与存储库对话以更改状态,但谁调用 DbContext.SaveChanges() 将其提交到数据库?
  • 服务层方法调用DbContext.SaveChanges.
  • 如何确保服务层引用存储库使用的相同 dbContext,以便协调所有相关更改?我是否在 Unity 中将其连接起来,以便它们都使用同一个对象?
  • 有几种方法。最简单的就是使用构造函数依赖注入;将 DbContext 作为参数传递给存储库的构造函数。使用最简单的解决方案来解决您的问题。你真的需要 Unity 吗?
  • 所以我可以让服务实例化一个 dbContext 对象,然后让它也创建它需要的存储库,将相同的 dbContext 对象传递给它们?
【解决方案2】:

是的,所以在进一步探索了这个问题之后,我得出了以下结论,所以我想我会在这里记录以帮助其他人,或者如果我的发现有误,我可以得到纠正。

DbContext 一个工作单元。我只需要将这个工作单元传递到已实现的 EFRepository 类中。它不需要进入服务类。那么一个Service类在没有DbContext实例的情况下如何调用context.SaveChanges()来保证所有相关的变化都得到协调呢?好吧,它调用了 EFRepository.Save(),如下所示:

public void Save()
    {
        context.SaveChanges();
    }

使用这种方法,服务类仅依赖于存储库。这将很清楚,可以模拟进行测试。当 Unity 将所需的 Repository 对象注入到 Service 中时,它可以为每个 Repository 提供相同的 DbContext。此外,只有 Repositories 可以访问 DbContext。

所有这些都可能是显而易见的,但它让我难住了。或者它可能是完全错误的,在这种情况下请告诉我!

詹姆斯

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-10
    • 2021-08-03
    • 2021-04-09
    • 2014-07-20
    • 2021-10-05
    • 2013-04-03
    相关资源
    最近更新 更多