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

在我工作的公司中,他们命令我更新和旧的MVC App并为SQL DB实现Repository Pattern。 我使用Entity Framework Database-First创建了数据库的上下文,并获得了23个实体。

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

每个域一个存储库

第二个问题:通用存储库是否适用于entity framework数据库优先? 这是因为我在搜索互联网时发现了以下内容:

实体框架

谢谢。

首先,如果您使用完整的ORM,如Entity Framework或NHibernate,您应该避免实现额外的存储库和工作单元层。 这是因为; ORM本身暴露了通用存储库和工作单元。
在EF的情况下,您的DbContext是工作单元, DbSet是通用存储库。 在NHibernate的情况下,它是ISession本身。
在相同的现有存储库上构建通用存储库的新包装器是重复工作。 为什么重新发明轮子?

但是 ,有些人认为在调用代码中直接使用ORM会产生以下问题:

  1. 它使代码变得更加复杂。
  2. 数据访问代码在业务逻辑中合并。
  3. 由于许多ORM对象在调用代码时在线使用,因此很难对代码进行unit testing。
  4. 由于ORM仅公开Generic Repository,因此会导致下面提到的许多问题。

除上述所有内容外,一般性讨论的另一个问题是“如果我们决定在未来改变ORM会怎么样”。 这不应该是决定时的关键点,因为:

  • 你很少改变ORM,主要是从不 – YAGNI。
  • 如果您更改ORM,则无论如何都必须进行大量更改。 您可以通过将完整的数据访问代码(不仅仅是ORM)封装在某些内容中来最小化工作量。 我们将在下面讨论这个问题。

考虑到上面提到的四个问题,即使您使用完整的ORM,也可能需要创建存储库 – 但这是根据具体情况做出的决定

即使在这种情况下,也必须避免使用通用存储库。 它被认为是一种反模式。

为什么通用存储库是反模式的?

  1. 存储库是正在建模的域的一部分,并且该域不是通用的。
    • 并非每个实体都可以删除。
    • 并非每个实体都可以添加
    • 并非每个实体都有一个存储库。
    • 查询变化很大; 存储库API变得与实体本身一样唯一。
    • 对于GetById() ,标识符类型可能不同。
    • 无法更新特定字段(DML)。
  2. 通用查询机制是ORM的责任。
    • 大多数ORM暴露出与Generic Repository非常相似的实现。
    • 存储库应该使用ORM公开的通用查询机制来实现实体的SPECIFIC查询。
  3. 无法使用复合键。
  4. 无论如何,它泄漏了服务中的DAL逻辑。
    • 如果您接受参数,则需要从服务层提供谓词条件。 如果这是特定于ORM的类,则会将ORM泄漏到服务中。

我建议你阅读这些( 1,2,3,4,5 )文章,解释为什么通用存储库是一种反模式。 这个其他答案一般性地讨论了存储库模式。

所以,我会建议:

  • 根本不要使用存储库,直接在您的调用代码中使用ORM。
  • 如果必须使用存储库,则不要尝试使用Generic Repository实现所有内容。
    相反,可选择创建非常简单和小型的通用存储库作为抽象基类。 或者,如果ORM允许,您可以使用ORM公开的Generic Repository作为基本存储库。
    根据您的需要实现具体的存储库,并从Generic Repository中获取所有这些存储库。 将具体存储库暴露给调用代码。
    通过这种方式,您可以获得通用存储库的所有优点,但仍然可以绕过其缺点。
    即使非常罕见,这也有助于在将来切换ORM,因为ORM代码在DAL /存储库中被完全抽象化。 请理解,切换ORM不是数据访问层或存储库的主要目标。

在任何情况下,都不要将Generic Repository暴露给调用代码。

另外,不要从具体的存储库中返回IQueryable 。 这违反了存储库存在的基本目的 – 抽象数据访问。 通过在存储库外部暴露IQueryable ,许多数据访问决策会泄漏到调用代码中,并且存储库将失去对它的控制。

我是否需要为每个实体创建存储库或为上下文实现通用存储库

如上所述,为每个实体创建存储库是更好的方法。 请注意,Repository理想情况下应返回Domain Model而不是Entity。 但这是讨论的不同主题。

通用存储库是否适用于EF Database First?

如上所述,EF本身公开了Generic Repository。 在它上面再建一层是没用的。 你的形象说的是同样的事情。