猿问

每个实体的通用存储库或特定存储库?

背景

在我工作的公司,我被要求更新旧的 MVC 应用程序并为 SQL 数据库实现存储库模式。我已经使用 Entity Framework Database-First 创建了数据库的上下文并获得了 23 个实体。


第一个问题

我是否需要为每个实体创建一个存储库或为上下文实现一个通用存储库?我问这个是因为我在搜索互联网时发现了以下内容:


每个域一个存储库


您应该将存储库视为内存中域对象的集合。如果您正在构建一个名为 Vega 的应用程序,您不应该拥有如下所示的存储库:


public class VegaRepository {}


相反,您应该为每个域类拥有一个单独的存储库,例如 OrderRepository、ShippingRepository 和 ProductRepository。


来源:使用 Mosh 编程:存储库模式的 4 个常见错误


第二个问题

通用存储库是否适用于实体框架数据库优先?这是因为我在搜索互联网时发现了以下内容:


实体框架


请注意,存储库模式仅在您有首先使用代码映射的 POCO 时才有用。否则,您只会用实体打破抽象(= 那时存储库模式不是很有用)。如果你想为你建立一个基础,你可以关注这篇文章。



杨__羊羊
浏览 188回答 1
1回答

德玛西亚99

首先,如果您使用完整的 ORM,如实体框架或 NHibernate,您应该避免实现额外的存储库和工作单元层。这是因为; ORM 本身公开了通用存储库和工作单元。在 EF 的情况下,您DbContext是工作单元并且DbSet是通用存储库。在 NHibernate 的情况下,它是ISession它本身。在相同的现有存储库上构建新的通用存储库包装器是重复工作。为什么要重新发明轮子?但是,有些人认为在调用代码中直接使用 ORM 存在以下问题:由于缺乏关注点分离,它使代码变得更加复杂。数据访问代码合并到业务逻辑中。结果,冗余的复杂查询逻辑分散在多个地方;很难管理。由于在调用代码中内嵌使用了许多 ORM 对象,因此很难对代码进行单元测试。由于 ORM 仅公开通用存储库,因此会导致下面提到的许多问题。除上述之外,另一个普遍讨论的问题是“如果我们决定将来更改 ORM 会怎样”。这不应该是做出决定时的关键点,因为:你很少改变 ORM,大多是从不——YAGNI。如果您更改 ORM,无论如何您都必须进行巨大的更改。您可以通过将完整的数据访问代码(不仅仅是 ORM)封装在某个东西中来最大限度地减少工作量。我们将讨论的东西下面。考虑到上面提到的四个问题,即使您使用的是完整的 ORM,也可能需要创建存储库 - 尽管这是每个案例的决定。即使在这种情况下,也必须避免使用通用存储库。它被认为是一种反模式。为什么通用存储库是反模式的?存储库是正在建模的域的一部分,该域不是通用的。并非每个实体都可以删除。并非每个实体都可以添加并非每个实体都有一个存储库。查询千差万别;存储库 API 变得与实体本身一样独特。对于GetById(),标识符类型可能不同。无法更新特定字段 (DML)。通用查询机制是 ORM 的职责。大多数 ORM 公开了一个与通用存储库非常相似的实现。存储库应该使用 ORM 公开的通用查询机制来实现实体的 SPECIFIC 查询。无法使用复合键。无论如何,它会泄漏服务中的 DAL 逻辑。如果您接受作为参数的谓词标准,则需要从服务层提供。如果这是 ORM 特定的类,它会将 ORM 泄漏到服务中。我建议您阅读这些(1 , 2 , 3 , 4 , 5)文章,这些文章解释了为什么通用存储库是一种反模式。这个另一个答案一般讨论了存储库模式。所以,我会建议:根本不要使用存储库,直接在调用代码中使用 ORM。如果您必须使用存储库,则不要尝试使用 Generic Repository 实现所有内容。相反,可以选择创建非常简单和小型的通用存储库作为抽象基类。或者,如果 ORM 允许,您可以使用 ORM 公开的通用存储库作为基础存储库。根据您的需要实施具体存储库,并从通用存储库中派生所有这些。向调用代码公开具体的存储库。通过这种方式,您可以在绕过其缺点的情况下获得通用存储库的所有优点。尽管非常罕见,但这也有助于将来切换 ORM,因为 ORM 代码在 DAL/Repositories 中被清晰地抽象出来。请理解切换 ORM 不是数据访问层或存储库的主要目标。在任何情况下,不要将通用存储库暴露给调用代码。另外,不要IQueryable从具体的存储库返回。这违反了存储库存在的基本目的 - 抽象数据访问。由于暴露IQueryable在存储库之外,许多数据访问决策泄漏到调用代码中,并且存储库失去了对它的控制。我需要为每个实体创建一个存储库还是为上下文实现一个通用存储库如上所述,为每个实体创建存储库是更好的方法。请注意,理想情况下,存储库应该返回域模型而不是实体。但这是不同的讨论话题。通用存储库是否适用于 EF Database First?如上所述,EF 本身公开了通用存储库。在它上面再建一层是没有用的。你的图片说的是同样的事情。
随时随地看视频慕课网APP
我要回答