【发布时间】:2012-03-24 07:22:40
【问题描述】:
我正在努力找出实体框架和存储库模式的理想实现。我使用的是 Entity Framework 4.3 代码优先,但我似乎无法很好地正确使用实体框架。
我喜欢 EF 为表格带来的东西,例如跟踪的实体、延迟加载、导航属性等。但据我所知,其中一些与存储库模式不兼容。让我们看几个例子,也许你们可以让我明白。
通用存储库与非通用存储库
我对通用存储库的最初印象是我不喜欢它,因为我不需要为每个实体提供完全相同的功能。例如,我有一个在数据库中存储简单变量(键/值对)的存储库。我不需要 Add 或 Delete 方法,因为这些是静态变量。我只需要一个 Update 方法和一个 Get 方法。通用存储库似乎不是很健壮,并且不允许在数据层中使用太多自定义代码。我也讨厌通用存储库返回IQueryable<T>,因为它使上层能够直接针对数据存储编写表达式,并且上层必须假设正在使用的数据访问技术正确实现了 IQueryable 以便查询数据库而不是将所有内容都拉入内存并从那里查询。
似乎通用存储库,尤其是返回 IQueryable 的存储库,并没有真正遵守良好的关注点分离。也许你们可以帮我清理一下,但现在我使用的是显式命名的存储库,并且只返回 IEnumerable 或 IList。
导航属性
我喜欢导航属性的概念,但在实现存储库模式时似乎很少使用它们。例如,我有一个具有名为“别名”的导航属性的用户。如果我想为用户添加别名,通过导航属性添加它会非常容易。
myUser.Aliases.Add(new Alias { Name="cls", Value="ClearScreen" });
但是我应该在哪里打电话给dbContext.SaveChanges()?我将myUser 传递给了我,我使用了导航属性来避免将IAliasRepository 注入我所在的类中。但是我现在无法将我的新别名保存到数据库中,因为我的上层是不知道实体框架。我现在必须注入我的IAliasRepository,这样我才能全部_aliasRepository.SaveChanges()。好吧,现在感觉完全是浪费。我觉得我应该改用_aliasRepository.AddAlias(newAlias),因为无论如何我都必须注入存储库。
自我跟踪实体
自我跟踪实体非常棒,但它们不适合您试图向应用程序的其余部分隐藏数据访问层详细信息的应用程序。例如,如果我正在编写存储库并且完全不知道他们会使用 EF,那么我肯定会添加一个 Update(Entity entity) 方法。但是,在 EF 中您不需要这样做,因为您可以简单地对实体进行更改,然后调用 SaveChanges()。该实体跟踪所有被修改的内容并将这些更改保存到数据库中。
var myEntity = _entityRepository.GetEntity("some unique ID");
myEntity.SomeProperty = "new value";
_entityRepository.SaveChanges();
如果我不知道 EF 不需要这些更新方法,我会删除这些更新方法。这使得重构变得更加困难,因为我可能不得不返回并添加适当的更新方法。我唯一的其他选择是无论如何都包含这些方法,然后在我实现我的存储库时对它们不做任何事情。
public void UpdateEntity(Entity entity)
{
// Do nothing. EF is tracking changes and they will be persisted when
// SaveChanges() is called.
}
所以我的代码看起来像这样,即使它完全没有必要。
var myEntity = _entityRepository.GetEntity("some unique ID");
myEntity.SomeProperty = "new value";
_entityRepository.UpdateEntity(myEntity);
_entityRepository.SaveChanges();
如果我只是想保持适当的关注点分离以便以后轻松重构,我想拥有一个空方法并不可怕,但这样做仍然感觉很有趣。
保持 DbContext 同步
此模式的另一个奇怪之处是您必须格外小心您的 DbContext。它的同一个实例需要注入到所有存储库中。否则,如果您将实体从一个存储库中拉出并尝试将它们与另一个存储库中的实体相关联,那么它们将无法很好地结合在一起,因为它们来自不同的 DbContext 实例。 IoC 容器使这更容易控制,但对于刚开始使用 EF 的开发人员来说,这是一个奇怪的问题。这里并不是一个真正的问题,而只是实体框架和存储库模式的另一个奇怪之处。
什么是使用 EF 的存储库模式的正确实现?你如何克服这些障碍?
【问题讨论】:
-
嗯,我注意到的一件事是,您似乎缺少工作单元模式。另外,我喜欢您对 IQueryable
. 的评论 -
@Hexxagonal 实际上我什至没有听说过“工作单元”模式。需要详细说明吗?
-
@Hexxagonal 我不久前写了一篇文章,详细介绍了为什么我认为 IQueryable 是一种糟糕的类型,如果您对一些简单的阅读感兴趣,那么从您的数据层返回:codetunnel.com/blog/post/103/…
-
对于 EF,我使用工作单元来包装上下文并保持所有存储库协同工作。此外,抽象出 EF 数据访问。当您混合和匹配数据库时,它尤其有用。谢谢你的博文,我去看看。
-
嗯,我想我真的对“工作单元”是什么感到迷茫。我得再用谷歌搜索一下。
标签: c# .net linq entity-framework entity-framework-4