工作单元和存储库模式对大型项目非常有用吗?

我正在使用ASP.NET Webforms + EF4开始一个新的Web项目。 我正在尝试按照本教程应用具有工作单元模式的存储库模式: http : //www.dotnetage.com/publishing/home/2011/07/05/6883/the-repository-pattern-with-ef -code先dependeny喷射在-ASP净mvc3.html

我想我有了这个想法,但我的问题是,当我在模型中创建一个新对象时,我是否还必须在工作单元的IDALContext中定义该对象? 这不是一个快速发展的手? 此外,如果您与多个开发人员合作,并且如果您不希望其他开发人员看到您的DAL,您如何管理它? 因为在我理解的这种模式中,当你在模型中创建一个新对象时,你还必须在本教程的IDALContext中定义它。 对不起,我对此很困惑。

Martin Fowler将存储库的角色描述为:“存储库在域和数据映射层之间进行调解,就像内存域对象集合一样”。 在这个意义上,entity framework4.1公开的一个存储库。 EF也有内置的统一工作。所以我的建议是忽略你在问题中提到的博客文章。

像这样的代码不仅无用或无价值而且危险,因为代码没有任何好处,而是依赖!

public interface IUnitOfWork:IDisposable { int SaveChanges(); } public interface IDALContext : IUnitOfWork { ICategoryRepository Categories { get; } IProductRepository Products { get; } } 

要回答您的问题,在域和数据映射层之间进行一些抽象调整,就像内存域对象集合一样,是“大”项目的必需品。 在引擎盖下使用UnitOfWork机制可以帮助将业务逻辑与访问某些数据访问抽象分离。

TL; TR; 存储库和UnitOfWork可以帮助您,但不要像给定的博客文章那样应用它。

现在,第一个问题应该是, 为什么我需要一个存储库或工作单元模式呢? 难道我不能只使用控制器的EF上下文,具有直接编写我需要的查询并返回数据的全部function吗?
答:你可以,但真正的意图是可测试性,从而提高质量,更易维护的代码。 如果您将数据访问分开并将其集中在一个地方,则可以在测试期间将其模拟出来。 这允许您对控制器中定义的逻辑进行单元测试,而无需有效地写入数据存储。

在开始使用工作单元之前,只需使用Repository模式 。 这基本上抽象了给定实体的数据访问。 因此,您可以定义Filter(),All(),Update(..),Insert(..),Delete(…)以及最后Save()等方法。 实际上,大多数这些都可以很容易地抽象到BaseRepository类,这样最终你只需要在极少数情况下创建一个具有特殊行为的新存储库。 否则它将类似于BaseRepository personRepo = new BaseRepository()BaseRepository

addressRepo = new BaseRepository
()

等。

为什么需要工作单位?
工作单元表示在特定周期内完成的所有操作,通常在每个Http请求的Web环境中。 这意味着当一个新请求进入时,你实例化一个新的工作单元,你添加新的东西,更新或删除它,然后你通过调用.save().commit()来“提交”更改。 实际上,如果你仔细看看Entity Framework DbContext(或ObjectContext),它们已经代表了某种工作单元。
但是,如果您想进一步抽象它,因为您不一定希望在控制器类中使用您的EF上下文(记住:可测试性),那么您创建一个UoW来对您的存储库进行分组,并确保它们共享相同的EF上下文实例。 您也可以通过DI容器(dependency injection容器)来实现后者。

问题:在大型项目中它是否有用?
当然,特别是在项目中。 这一切都是为了保持职责分离(数据访问,业务逻辑,域逻辑),从而使事情变得可测试。

软件设计模式旨在通过正确的上下文解决特定问题,如果使用不当,它们将导致额外的不必要的复杂性而不提供任何值。

那么,存储库模式旨在解决的问题是什么?

1-最小化重复查询逻辑 :在大型应用程序中,您可能会发现许多复杂的LINQ查询在一些地方重复。 如果是这种情况,您可以使用存储库模式来封装这些查询并最大限度地减少重复。

2-更好地分离关注点:想象一个复杂的查询,以获得特定类别中的畅销课程,包括急切加载,加入,分组,过滤等。

当您在服务/控制器中实现如此大的复杂查询时,您将最终得到胖服务/控制器。 这些类很难进行unit testing,因为它们需要大量的噪声存根。 您的unit testing变得冗长,肥胖且无法维护。

如果您遇到此问题,也许您可​​以考虑使用存储库模式。 在此示例中,我们可以封装复杂查询以获取存储库中的畅销课程:

 courseRepository.GetTopSellingCourses(int categoryId, int count); 

这样,您的服务/控制器将不再处理急切的加载,加入,分组等。相反,它们将委托给存储库。 请记住,急切加载,加入和分组等都是查询逻辑,属于您的数据访问层,而不是您的服务或表示层。

3- 将应用程序体系结构与持久性框架分离:当您在应用程序中直接使用Entity Framework类(例如DbContext,DbSet等)时,您的应用程序与entity framework紧密耦合。 如果您计划在将来的某个时间切换到不同的O / RM,或者甚至是使用不同型号的更新版本的Entity Framework,您可能必须修改应用程序的许多部分,这可能会导致应用程序出现新的错误。 您可以使用存储库模式将应用程序体系结构与entity framework等持久性框架分离。 这样,您就可以自由地更改为不同的O / RM,而对应用程序的影响最小。

观看此video了解更多详情:

https://youtu.be/rtXpYpZdOzM

您应该考虑“命令/查询对象”作为替代,您可以在这个区域找到一堆有趣的文章,但这里有一个很好的文章:

https://rob.conery.io/2014/03/03/repositories-and-unitofwork-are-not-a-good-idea/

您将坚持使用每个命令的单个命令对象来启用简单事务,从而避免了对工作单元模式的复杂性的需要。

但是,如果您认为每个查询的查询对象过度,那么您可能100%正确。 通常,您可以选择以“FooQueries”对象开头,该对象本质上是一个存储库,但仅用于查询。 ‘Foo’可能是DDD意义上的’域聚合’。

您可能会在以后找到有价值的查询对象。

与大多数事情一样,您必须在系统基础上考虑。