实体框架,导航属性,以及库模式 [英] Entity Framework, Navigation Properties, and the Repository Pattern

查看:215
本文介绍了实体框架,导航属性,以及库模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在努力找出理想的实现实体框架和存储库模式。我使用实体框架4.3 code-第一,我只是似乎无法环绕实体框架的良好的正确用法我的头。

我喜欢的东西EF带来的表,如跟踪的实体,延迟加载,导航属性等,但其中的一些不玩好与资料库的模式,我理解这一点。让我们看几个例子,也许你们可以把我直。

通用库VS非通用信息库

通用仓库的我最初的即时通讯pression的是,我不喜欢它,因为我并不需要为每个实体完全相同的功能。例如,我有一个简单的存储变量(键/值对)在数据库中的存储库。我不需要添加或删除的方法,因为这些都是静态变量。我只需要一个更新的方法和Get方法。通用库似乎并不非常稳健,不允许太​​多的定制code中的数据层研究。我也很讨厌当通用信息库返回的IQueryable< T> ,因为它给上层直接对数据存储写EX pressions的能力,上层有假设被正确使用的数据访问技术实现IQueryable的,这样它的查询数据库,而不是拉一切到内存中,并从那里查询它。

这似乎只是普通的储存库,特别是那些返回IQueryable的,真的不坚持关注良好的分离。也许你们可以清除一个为我,但现在我使用明确命名的存储库,只返回了IEnumerable或IList的。

导航属性

我爱导航属性的概念,但它好像我很少得到执行存储库模式时使用它们。举例来说,我有一个所谓的别名导航属性的用户。如果我想补充的别名,用户将是超级容易通过导航属性添加它。

  myUser.Alias​​es.Add(新别名{名称=CLS,值=ClearScreen});
 

但后来我在哪里叫 dbContext.SaveChanges()?我有 MYUSER 传递给我,我用的导航属性,以避免注入我的 IAlias​​Repository 进级我米,但我现在没有办法坚持我的新别名数据库,因为我的高层都不知情实体框架。我现在有注入我的 IAlias​​Repository 反正只是这样我就可以全部 _aliasRepository.SaveChanges()。现在好了,感觉像一个完整的浪费。我觉得我应该只是用 _aliasRepository.AddAlias​​(newalias将),而不是因为我有仓库反正注入。

自跟踪实体

自跟踪实体是真棒,但他们不能够很好的应用,你试图隐藏从应用程序的其余部分的数据访问层的详细信息。举例来说,如果我写的存储库和被完全无知,他们将使用EF话,我会最肯定添加更新(实体实体)方法。然而,在EF你不需要这么做,因为你可以简单地更改一个实体,然后调用的SaveChanges()。实体跟踪被修改一切,坚持那些对数据库的更改。

  VAR myEntity所= _entityRepository.GetEntity(一些独特的ID);
myEntity.SomeProperty =新价值;
_entityRepository.SaveChanges();
 

这使我消除,我会已包括了我并不知道EF不需要他们我的更新方法。这使得再保下山的路更难,因为我可能会回去,并添加适当的更新方法。我唯一​​的其他选择是无论如何包括方法,然后就什么也不做与他们,当我实现我的存储库。

 公共无效UpdateEntity(实体实体)
{
    // 没做什么。 EF是跟踪变化,它们将被保存时
    //调用SaveChanges()被调用。
}
 

所以,我的code是这样的,即使它是完全没有必要的。

  VAR myEntity所= _entityRepository.GetEntity(一些独特的ID);
myEntity.SomeProperty =新价值;
_entityRepository.UpdateEntity(myEntity所);
_entityRepository.SaveChanges();
 

我想有一个空方法并不可怕,如果我只是想保持轻松重构后的担忧适当分离,但仍觉得好笑做到这一点。

保持的DbContext同步

另一个奇怪的怪癖,这种模式是,你必须要格外小心你的DbContext。它的同一个实例需要被注入到所有存储库。否则,如果你拉出来的实体一个版本库,并尝试将其与实体从另一个存储库相关联的话,他们就不会发挥好起来,因为他们是从的DbContext的不同实例。 IoC容器中,使这更容易控制,但它的开发才刚刚开始与EF一个奇怪的问题。不是一个真正的问题就在这里这么多只是一个怪胎与实体框架和资源库的模式。

什么是正确的执行与EF仓库模式?如何克服这些障碍?

解决方案
  

通用库VS非通用信息库

通用仓库不是一个模式。 <一href="http://stackoverflow.com/questions/5625746/generic-repository-with-ef-4-1-what-is-the-point/5626884#5626884">Generic库只是一个包装。它可以用于一些特殊的情况下,作为特定的存储库的基类是有用的,但在大多数情况下,它只是在使用和过度炒作的废话。

  

导航属性。

库本身应使用聚合根。的总根源是,你必须储存库只为主体,因为依赖离不开父母存在多个相关实体的聚集。库本身处理负荷,坚持所有的实体类型的集合。

即使总根源,你将结束与一些挑战。例如如何处理许多一对多的关系?多对多关系随时重新present场景,有没有真正的委托人或相关实体=他们不在聚集。如果你只能通过导航属性设置这两个实体之间的关系,它仍然是确定的,但EF您还可以通过导航属性创建相关的实体,它在某种程度上违反了信息库的目的。你可以执行你的资料库,以测试是否存在关系,但它可能会导致大量的额外的查询,所以你将最有可能离开它的实施为漏水的抽象。

  

自跟踪实体

这是你的code我想你混淆<一个href="http://stackoverflow.com/questions/5091974/what-is-the-purpose-of-self-tracking-entities/5092097#5092097">self-tracking实体的附加实体。你描述的是连接和分离的实体之间的差异。如果你想支持这两种方案在单个code本 UpdateEntity 方法具有意义,因为你必须测试,如果实体连接,将其安装+设置的状态,如果没有。

  

保持的DbContext同步

这是你在哪里丢失的工作单位。仓库本身的包装只有查询和存储实体的来龙去脉,但工作单位处理上下文创建/ retireval,坚持更改数据库中。作为例子,你可以把 DbSet (EF英孚的实现库)和的DbContext (EF英孚的落实工作单元)。

I am struggling to figure out the ideal implementation of Entity Framework and the repository pattern. I'm using Entity Framework 4.3 code-first and I just can't seem to wrap my head around good proper usage of entity framework.

I love the things EF brings to the table such as tracked entities, lazy loading, navigation properties, etc. But some of these don't play nice with the repository pattern as I understand it. Let's look at a few examples and maybe you guys can set me straight.

Generic Repository vs Non-generic Repository

My initial impression of the generic repository is that I don't like it because I don't need the exact same functionality for every entity. For example, I have a repository that stores simple variables (key/value pairs) in the database. I don't need an Add or Delete method because these are static variables. I only need an Update method and a Get method. The generic repository just doesn't seem very robust and doesn't allow for much custom code in the data layer. I also hate when generic repositories return IQueryable<T> because it gives the upper layers the ability to write expressions directly against the data store, and the upper layers have to assume that the data access technology being used properly implements IQueryable so that it's querying the database and not pulling everything into memory and querying it from there.

It just seems like generic repositories, especially ones that return IQueryable, don't really adhere to good separation of concerns. Maybe you guys can clear that one up for me, but right now I'm using explicitly named repositories and only returning IEnumerable or IList.

Navigation Properties

I love the concept of navigation properties, but it seems like I rarely get to use them when implementing the repository pattern. For instance, I have a user with a navigation property called "Aliases". If I want to add an Alias for a user it would be super easy to add it via the navigation property.

myUser.Aliases.Add(new Alias { Name="cls", Value="ClearScreen" });

But then where do I call dbContext.SaveChanges()? I had myUser passed to me and I used the navigation property to avoid having to inject my IAliasRepository into the class I'm in. However I now have no way to persist my new alias to the database because my upper layers are unaware of Entity Framework. I now have to inject my IAliasRepository anyway just so I can all _aliasRepository.SaveChanges(). Well now that feels like a complete waste. I feel like I should have just used _aliasRepository.AddAlias(newAlias) instead since I have to have the repository injected anyway.

Self-Tracking Entities

Self-tracking entities are awesome but they don't lend themselves well to applications where you're trying to hide the data access layer details from the rest of the app. For instance, if I were writing repositories and being totally ignorant that they would be using EF then I would most definitely add an Update(Entity entity) method. However, in EF you don't need to do that because you can simply make changes to an entity and then call SaveChanges(). The entity tracks everything that was modified and persists those changes to the database.

var myEntity = _entityRepository.GetEntity("some unique ID");
myEntity.SomeProperty = "new value";
_entityRepository.SaveChanges();

This causes me to eliminate my update methods that I would have included had I not been aware that EF doesn't need them. This makes re-factoring harder down the road because I may have to go back and add proper update methods. My only other option would be to include the methods anyway and then just do nothing with them when I implement my repositories.

public void UpdateEntity(Entity entity)
{
    // Do nothing. EF is tracking changes and they will be persisted when
    // SaveChanges() is called.
}

So my code would look like this, even though it's completely unnecessary.

var myEntity = _entityRepository.GetEntity("some unique ID");
myEntity.SomeProperty = "new value";
_entityRepository.UpdateEntity(myEntity);
_entityRepository.SaveChanges();

I suppose having an empty method isn't terrible if I'm just trying to maintain proper separation of concerns for easy refactoring later, but it still feels funny to do that.

Keeping DbContext in sync

Another weird quirk of this pattern is that you have to be extra careful with your DbContext. The same instance of it needs to be injected into all repositories. Otherwise if you pull entities out of one repository and try to associate them with entities from another repository then they won't play nice together because they are from different instances of DbContext. IoC containers make this easier to control, but it's an odd issue for developers just beginning with EF. Not really a problem here so much as just another oddity with Entity Framework and the repository pattern.

What is the proper implementation of the repository pattern with EF? How do you overcome these hurdles?

解决方案

Generic Repository vs Non-generic Repository

Generic repository is not a pattern. Generic repository is just a wrapper. It can be useful for some special scenarios as a base class for specific repositories but in most cases it is just over used and over hyped nonsense.

Navigation properties

Repository itself should be used with aggregate root. The aggregate root is aggregation of multiple related entities where you have repository only for principal because dependencies cannot exist without parent. Repository itself handles loading and persisting all entity types in aggregation.

Even with aggregate roots you will end with some challenges. For example how to handle many-to-many relations? Many to many relation always represent scenario where there is no real principal or dependent entity = they are not in aggregation. If you only set relation between these two entities through navigation property it is still OK but EF also allows you creating related entity through navigation property and it somehow violates repository purpose. You can enforce your repository to test existence of relations but it can cause a lot of additional queries so you will most probably leave it as leaky abstraction of your implementation.

Self-Tracking entities

From your code I think you confused self-tracking entities with attached entities. What you describe is difference between attached and detached entities. If you want to support both scenarios in single code your UpdateEntity method has a meaning because you must test if entity is attached and attach it + set state if not.

Keeping DbContext in sync

This is where you are missing unit of work. Repository itself wraps only queries and storing entities into context but unit of work handles context creation / retireval and persisting changes to database. As example you can take DbSet (EF's implementation of repository) and DbContext (EF's implementation of unit of work).

这篇关于实体框架,导航属性,以及库模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆