c# – 实体框架,导航属性和存储库模式

我正在努力弄清楚Entity Framework和存储库模式的理想实现。我使用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()?我有我的用户传递给我,我使用导航属性,以避免注入我的IAliasRepository到我的类中。但是我现在没有办法坚持我的新别名到数据库,因为我的上层不知道Entity Framework 。我现在不得不注入我的IAliasRepository只是所以我可以全部_aliasRepository.SaveChanges()。现在,感觉像一个完整的浪费。我觉得我应该使用_aliasRepository.AddAlias(newAlias),因为我必须有注册的存储库。

自我跟踪实体

自我跟踪实体非常棒,但它们不适用于您试图从应用程序的其余部分隐藏数据访问层详细信息的应用程序。例如,如果我正在编写存储库,并完全无知他们将使用EF,那么我将绝对添加一个更新(实体实体)方法。但是,在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的开发人员来说,这是一个奇怪的问题。这里真的不是一个问题,因为只是另一个奇怪的Entity框架和存储库模式。

什么是适当的实现存储库模式与EF?你如何克服这些障碍?

Generic Repository vs Non-generic Repository

通用资源库不是模式。 Generic repository is just a wrapper.它对于一些特殊情况可能是有用的,作为特定存储库的基类,但在大多数情况下,它只是过度使用和overed废话。

Navigation properties

存储库本身应与聚合根一起使用。聚合根是多个相关实体的聚合,其中只有主体的存储库,因为依赖关系不能没有父存在。存储库本身处理加载并在聚合中保留所有实体类型。

即使有聚合根,你会结束一些挑战。例如如何处理多对多关系?多对多关系总是表示没有真正的主体或从属实体的情况。它们不在聚合中。如果你只通过导航属性设置这两个实体之间的关系仍然可以,但EF还允许你通过导航属性创建相关的实体,它以某种方式违反了存储库的目的。你可以强制你的存储库来测试关系的存在,但它可以导致大量的额外的查询,所以你很可能将它作为漏洞抽象的实现。

Self-Tracking entities

从你的代码我认为你困惑self-tracking entities与附加实体。你描述的是附加的和分离的实体之间的区别。如果你想在单个代码中支持这两种情况,你的UpdateEntity方法有一个意义,因为你必须测试实体是否附加并附加它设置状态,如果没有。

Keeping DbContext in sync

这是您缺少工作单元的地方。存储库本身只包括查询和将实体存储到上下文中,但工作单元处理上下文创建/退出并持久保存对数据库的更改。作为例子,你可以采取DbSet(EF的库的实现)和DbContext(EF的实现的工作单元)。

http://stackoverflow.com/questions/9590069/entity-framework-navigation-properties-and-the-repository-pattern

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:c# – 实体框架,导航属性和存储库模式