使用Entity Framework的仓储模式

20

仓储模式用于抽象出特定数据库和对象关系映射技术(如EF)的使用,这样我如果决定更换(例如),我可以轻松地将我的Entity Framework映射替换为Linq to SQL。

但是,当我使用EF时,我的实体类来自模型-也就是说,它们是从那个可视化图表生成的。 如果我在仓储中使用这些生成的实体类,然后决定用其他东西替换EF,那么我将删除那个可视化实体图并删除类,对吧?

我要解决的问题是,我的仓库将依赖于Entity Framework,也就是数据访问层,因为它将使用由EF生成的类。

我应该如何消除这种依赖性?

还请注意,我主要使用EF,是因为其能够从那个可视化图表生成所有内容-我只需设计图表,让它为我生成带有所有外键的数据库。 我非常喜欢这个功能,不想去考虑SQL命令。

4个回答

29

一个仓库(repository)总是依赖于数据访问技术。这就是人们使用仓库的原因 - 将数据访问的依赖封装到单独的层中。如果您决定更改数据访问技术(在我看来可能性只有1%),则必须创建新的仓库来实现与以前相同的接口。

引入仓库将增加一层复杂性。仓库有其优点和缺点。仅仅因为“您可以在未来更改数据访问方式”而引入它们是一个不好的理由。不要基于可能发生的事情来设计应用程序。根据当前的真实需求设计应用程序(敏捷方式),如果需要更改代码,请进行重构 - 这是保持市场竞争力的唯一方法。特性是销售您的软件,而不是为了任何类型的更改而开放的架构(当然,有例外情况,但在这种情况下,这种开放的架构是一个最高级别的要求)。

使用EF时,您有几个选择来创建实体:

  • 使用自定义工具生成实体对象。这是默认的方法,它会为EDMX创建“代码后备”文件。这是EFv1(.NET 3.5 SP1)中唯一可用的解决方案。
  • 使用T4模板生成实体对象、POCOs、STE或任何自定义实体类型(您可以修改生成逻辑)。这通常与EFv4一起使用。
  • 自己编写POCOs。这可以在EFv4中使用,并且在EF 4.1的代码优先方法中始终使用。

如果您期望数据访问技术将来可能会发生变化,请使用第二种或第三种方法来创建POCOs。在使用T4模板的情况下,您可以简单地复制生成的POCOs,或者修改项目文件以便在删除EDMX文件后不会失去它们。

如果您不确定第二种或第三种方法是否适合您,请查看我的答案:

因为我某种程度上同意@Patko的答案,所以你也应该查看Ayende的博客。他写了几篇关于过度使用存储库和过度架构应用程序的文章。他在写关于NHibernate,但是类似的决策可以在EF中做出。唯一的区别是NHibernate提供更好的抽象化,因此直接使用NHibernate的代码更易于测试。


@Ladislav Mrnka 首先,我不同意“不要因为某些事情可能发生而设计您的应用程序”。我总是尝试使我的代码健壮和防御性,并且通常在以后证明这是一个好决定。几行额外的代码可以节省重构和调试的时间。如果“不要因为某些事情可能发生而设计您的应用程序”是真的,那么很少有项目会使用存储库(除了那些需要从一开始就支持2种持久性存储技术的项目)。其次,我只是感到将上下文引用传递给服务层让人感到不舒服,所以我需要一些DAL来包装它。 - Rasto
1
@drasto:如果您足够熟练,可以就架构做出专业决策,那么这种方法是可以的。但在回答和阅读有关EF和存储库的许多问题后,我认为许多开发人员正在过度设计他们的应用程序。从一开始就拥有两种数据访问技术是引入存储库的一个很好的理由,但您在问题中没有提到它。 - Ladislav Mrnka
@Ladislav Mrnka,我一开始并没有使用两种数据访问技术,那只是为了说明如果每个人都采用你的“不要因为某些事情可能发生而设计应用程序”的方法,那么只有需要存储库的应用程序可能需要从一开始就支持2种数据访问技术。实际上,我不认为很快会需要更改数据访问技术。我只是觉得将ObjectContext实例传递到服务层中的服务很糟糕...我认为一些包装EF的中间DAL会更清晰(即使EF也是一种DAL)。 - Rasto
1
@drasto,我猜拉迪斯拉夫想说的是,你需要有有效的理由来引入仓储库的抽象。如果你不想在服务层中依赖EF,并且认为仓储模式可以帮助你解决这个问题,那么这已经是足够有效的理由了;可能还有其他的解决方案,但这是你的选择。 - Rodi
@Ladislav 如果nHibernate有更好的抽象化,那么它可能对此有所帮助,但是我喜欢使用一个“规则”(来自GOOS书籍):“只模拟您拥有的类型”,因此即使使用nHibernate(作为适配器),我也会引入抽象化。(顺便说一句,您在EF和相关对象方面有一些很棒的帖子和答案;感谢您帮助我们这些新手) - Rodi
显示剩余3条评论

9

有能力从一种持久化技术切换到另一种是很好的,但你真的需要吗?

首先,什么是存储库?根据Fowler的定义,它提供了对域对象的类似于内存集合的访问。但是,每个现代ORM工具都已经做到了这一点,所以另一个抽象层只会增加更多的复杂性。

其次,从一种持久化技术切换到另一种通常比提供另一个存储库实现更复杂。例如,您打算如何处理事务?事务通常取决于上下文并在存储库之外处理。当然,您可以使用某种工作单元实现,但那么您将不得不为每种持久化技术实现新的工作单元。

我并不是说您不应该使用存储库,只是也许再考虑一下。


我仍在考虑我的选择。我有一个ASP.NET MVC应用程序,持久性无法正常工作...它的设计非常糟糕。所以这一次我将不得不从头开始重新构建,并以一种方式进行,使我能够根据正在开发的业务逻辑需求轻松更改模型(我现在正在处理)。那么你建议我做什么?我应该只是将ObjectContext的实例传递给服务层中的服务吗?我对此感到有些不好... - Rasto
3
+1 是因为我同意这个观点。"Repository"(仓储)这个词已经被过度使用了,并且在任何现代 ORM 工具出现之前就已经定义了。 - Ladislav Mrnka
3
也许你可以看一下 Ayende 的博客,链接是 http://ayende.com/Blog/default.aspx。他曾经是 repository 模式的倡导者,但现在改变了主意。这是从这篇博客文章 http://ayende.com/Blog/archive/2009/04/17/repository-is-the-new-singleton.aspx 开始的。他最近的博客也提供了一些关于如何做到的想法。至于 ObjectContext,我不知道为什么不行。如果你传递 repository 会感觉更好吗?只需将 ObjectContext 视为一种 repository 即可 :) - Patko
那很有意义。ObjectContext本身就是一种数据访问层(DAL)。 - Rasto

6
EF设计器创建的实体类在您的项目中,位于您的“Model.Designer.cs”中。您可以复制代码,这样即使删除了模型或EF的引用,实体也仍然存在于您的项目中。 但是,它们与EF紧密耦合,因此您应该努力将EF与实体类解耦。
到目前为止,您有T4模板可帮助您进行解耦,但它们仍需要对所选的T4进行一些更改:
ADO.NET EntityObject Generator ADO.NET POCO Entity Generator ADO.NET Self-Tracking Entity Generator EF4.1提供了一个简化的API DbContext,它可以在您想要解耦实体类时提高您使用EF的体验。使用EF4.1,您可以采用以下3种方法:
Code First 您创建类,EF按照应该的方式创建DB 删除对EF的引用后,类不会消失 没有设计器
Database First 如果您已经拥有数据库,则会为您创建一个模型 您可以使用新的T4模板DbContext Generator创建实体类
Model First 像您现在做的那样,在设计器中创建模型 您可以使用DbContext Generator创建实体类
现在回答您的问题:
如何删除此依赖关系?
安装EF4.1 创建您的模型(使用Model-first方法) 从模型生成数据库 使用DbContext Generator生成实体类
您可以在此处查看如何执行所有这些操作:EF 4.1 Model & Database First Walkthrough。 您应该阅读ADO.NET Team Blog系列文章Using DbContext in EF Feature CTP5 Part 1: Introduction and Model(EF4.1以前称为EF Feature CTP5)中的内容。 您可以在我的问题中获取更多详细信息:EF POCO code only VS EF POCO with Entity Data Model

+1 现在你是显然的赢家。我曾经决定使用 T4 模板来生成 POCO 实体,然后尝试找出如何使框架在我更改模型时自动重新创建数据库表。但我目前更喜欢你的建议-看起来用简化的 API 比 T4 模板更容易实现。我还有一个问题:在使用 Model First 方法时,是否可能每次更改模型时都将我的数据库表与 POCO 类一起自动重新创建?我该如何做到这一点? - Rasto
我知道使用Code First方法可以自动生成表格。 - Rasto
我已经提出了另一个问题,这是由你在这里的回答所启发的,请随意发布一些答案。https://dev59.com/u1XTa4cB1Zd3GeqP2YNP 。无论如何,谢谢。 - Rasto
@drasto 当您更改模型时,可以手动重新创建数据库。只需删除数据库并重新生成即可。但是,您也将失去任何测试数据。正如您上面所说,使用Code First,可以自动生成和填充数据库:http://thedatafarm.com/blog/data-access/seeding-a-database-with-ef4-code-first/ - Nelson Reis

3
在Entity Framework 4版本中的新功能之一是“Code First”开发。这将允许你使用普通的C#(POCO)类与实体框架进行交互。以这种方式编写类后,你可以编写一个不同的库存储机制的实现来持久化这些类。 ScottGu在他的博客文章中包含了更多信息。

1
实际上,这不是EFv4的功能,而是一个名为EF 4.1的单独版本。 - Ladislav Mrnka
+1 我喜欢它。不仅因为有独立的类,还因为能够在我对模型类进行更改时重新创建数据库。但是有一件事我不喜欢——就是要编写所有类及其属性——我预计我的模型将有大约50-70个类。在可视化设计师中看起来更好。所以我希望有像“1.创建可视化模型图2.让VS从图中生成POCO类3.让EF从POCO类生成表外键等,或者(更好的是)让其他工具从POCO类生成EF图”的东西。 - Rasto
@drasto - EF的设计带来的一个普遍批评是在使用大量实体时它非常笨拙。很奇怪你有相反的问题。@Sean Reily - 你的答案是不正确的。4.1中的“Code First”并没有使您能够使用POCO类,这在4.0中就已经可以了。微软后来发布了t4模板,使这一过程更加容易。http://visualstudiogallery.msdn.microsoft.com/23df0450-5677-4926-96cc-173d02752313 - John Farrell
@jfar - 我说的是4.0(引用ScottGu)。其他人提到了4.1。 - Sean Reilly
在EF 4.0中,您可以使用POCOs,但是如果您不通过代码生成概念模型和映射,则不被视为Code-First。 - Danny Varod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接