31

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?

CatDadCode
  • 58,507
  • 61
  • 212
  • 318
  • Hm, well, one thing I noticed is that it seems like you are missing the Unit of Work pattern. Also, I like your comment about IQueryable. – scottheckel Mar 06 '12 at 19:11
  • @Hexxagonal I've actually not even heard of the "Unit of Work" pattern. Care to elaborate? – CatDadCode Mar 06 '12 at 19:14
  • @Hexxagonal I wrote a post a while back with more details why I think IQueryable is a terrible type to return from your data layer if you're interested in some light reading: http://www.codetunnel.com/blog/post/103/should-you-return-iqueryablet-from-your-repositories – CatDadCode Mar 06 '12 at 19:30
  • For EF, I use Unit of Work to wrap the context and keep all the repositories working in tandem. Also, to abstract out the EF data access. It especially helps when you're mixing and matching DBs. Thanks for the blog post, I'll check it out. – scottheckel Mar 06 '12 at 20:17
  • Hmmm, I guess I'm just really lost as to what "Unit of Work" is. I'll have to do some more Googling. – CatDadCode Mar 06 '12 at 20:20
  • @Alex I have been reading up on using the repository pattern in c# and very much agree with your post about IQueryable. I am interested in using EF but don't want my repository to depend on it. Do you have any example source code of how you have your repository pattern setup? I have been looking at several examples and am curious as to how you approached it. – stevosaurus Mar 06 '12 at 20:37
  • @stevosaurus I do actually. The project I'm working on is open source at http://github.com/Chevex/CT-Terminal. Just have a look in the Terminal.Domain project. The Entities folder contains my EF 4.3 code-first entities and the Repositories folder contains all my repositories and associated interfaces. Though keep in mind that I'm questioning my own implementation :P – CatDadCode Mar 06 '12 at 20:40
  • @Alex Great, thanks for the link. It will give me some more to chew on :). I am leaning towards the POCO route as it seems most flexible even though it may be a bit more work up front. – stevosaurus Mar 06 '12 at 20:53
  • @stevosaurus I really love code-first in EF 4.3. You'll notice I'm using the new Migrations stuff. If you pull down that project all you have to do is press F5 and the app will run and setup the entire database for you locally. It even migrates the schema to the latest version on first run. Whatever you go with, code-first comes highly recommended by me. – CatDadCode Mar 06 '12 at 20:59
  • I'm considering just going with [this post](http://stackoverflow.com/a/5007221/498624) to abstract out DbContext for testing. Then just eliminating my current repository pattern. It's just causing me so many headaches. – CatDadCode Mar 06 '12 at 21:04
  • [This article](http://blogs.msdn.com/b/adonet/archive/2009/06/16/using-repository-and-unit-of-work-patterns-with-entity-framework-4-0.aspx) is worth a read. I think it describes what I'm looking for. All this time I've been adding SaveChanges() methods to my repositories when I could be abstracting that out into the "Unit of Work" people keep talking about. – CatDadCode Mar 06 '12 at 21:28

1 Answers1

15

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).

Community
  • 1
  • 1
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • Okay, so I think I need a technical translator for your response to Navigation Properties. What do you mean by "aggregate root"? Also with DbContext I'm not quite sure what you mean by "unit of work". – CatDadCode Mar 06 '12 at 20:11
  • Maybe a better question would be, "How would you change my existing repository pattern?" Currently I have about 20 different repositories (one for every entity) and each of those repositories has DbContext injected by Ninject. Switching data access implementations is a very real possibility with this particular application so I do think I want repositories, but maybe you have a better idea? – CatDadCode Mar 06 '12 at 20:18
  • You can see my implementation of the repository pattern in my project itself if you wish. http://github.com/Chevex/CT-Terminal. I'm genuinely curious what you think. – CatDadCode Mar 06 '12 at 20:41
  • After much thinking and Googling I think I finally get what you're trying to tell me about "Unit of Work" I'm still not sure what you meant about navigation properties, but the unit of work idea makes sense. – CatDadCode Mar 06 '12 at 21:37
  • @AlexFord: to understand what "aggregate root" is, try researching on "Domain Driven Design" >> DDD. – Samuel Mar 12 '12 at 07:14