23

I'm laying out a new data layer using EF 4.1 Code First, migrating from an older homebrew data layer.

I have set up two assemblies, one for my context and one for all the POCO code first classes.

I have some business logic, for instance, a query against one table (or a few tables) that is used in several different places. Where should I put it?

It can't go in a POCO class because it joins a couple tables and so needs a context. It could go in the context, but that context would become bloated with hundreds of disorganized queries. Is there a common pattern or arrangement for all the business logic?

Ladislav Mrnka
  • 349,807
  • 56
  • 643
  • 654
Scott Stafford
  • 40,202
  • 22
  • 116
  • 163

3 Answers3

75

Looks like the repository pattern is solution for everything ... Repository is not a silver bullet!

I'm using the repository pattern with EF everyday because when I started my current project several months ago it looked like recommended solution. My conclusions:

  • Repository makes interaction with EF much harder. Just browse questions related to EF tags and you will see what complexities must be handled directly on the context, changetracker, etc.
  • Generic repository is something that works for CRUD operations but not for real DDD scenarios. Once your repository works with aggregate roots (DDD) generic approach fails.
  • Unit testing doesn't work at all because general idea that you will mock repository and test your upper layer without dependencies to EF and database fails once you expose IQueryable. Linq-to-entities is only subset of Linq-to-objects and mock doesn't handle referential integrity so many times I saw green unit tests and runtime exceptions. The correct testing approach with EF are integration tests. Mocking repository is only for testing real business logic not related to data access. If you don't have integration test for your business method accessing or persisting data you didn't test it.
  • Exposing specialized methods like GetByXXX is just step back. Most of these methods are used only once. You will end with the code similar to repositories used for wrapping stored procedures calls. Many developers like ORM just because they can avoid such rigid architecture.

EF itself already offers repository pattern - DbSet and ObjectSet are repositories and DbContext and ObjectContext are Unit of works. So in my opinion repository pattern is overused. It can be useful in large projects where you need strict layering or in case of placing additional logic to its methods. Using repository just because you want to wrap access to EF is often valueless code and just additional layer of complexity.

You can in the same way create reusable methods defining your queries.

Leniel Maccaferri
  • 94,281
  • 40
  • 348
  • 451
Ladislav Mrnka
  • 349,807
  • 56
  • 643
  • 654
  • 8
    +1 I used to be in the Repository camp all the way, but I concur with everything stated in this post - it just makes a lot of things much harder and less clean than they are supposed to be. Since it's baked into my current design I will have a hard time giving it up now, but starting from scratch I'd think twice about it. – BrokenGlass Mar 30 '11 at 16:10
  • 2
    I see your points here, however you did not offer alternative solution? Services passing Specifications as constraints (Lambdas)? How do you/would you setup data access? – Paul Mar 30 '11 at 16:42
  • 1
    That was my sense too... but can you elaborate on how you'd organize the suggestion you made "You can in the same way create reusable methods defining your queries." -- exactly, where? – Scott Stafford Mar 30 '11 at 17:37
  • @Scott: I have to say, I'm not 100% sure because my experience is only with repositories. But for small projects I can definitely imagine using EF directly in business methods. Reusable queries can be defined as separate methods or extensions to `IQueryable`. But those are only assumptions which I didn't have chance to verify in real scenarios. My current experience is - repository is very nice pattern but using it doesn't make things simple. – Ladislav Mrnka Mar 30 '11 at 17:46
  • So then your business methods depend on EF. And what happens when you want to reuse the code for SQL CE or NHibernate? – Tae-Sung Shin Aug 12 '11 at 20:49
  • 6
    @Teasung: I don't deal with "what happens if" - I'm paid for delivering features which are required now no for preparing my application for every scenario which can somehow in the future happen. Once it happens I will have to make big changes anyway. ORM is leaky abstraction and if you want to take full advantages of its features you wil still have some hidden dependency in your code (and it doesn't have to be reference to EF but some logic build in the way that is expected by used ORM). I saw several projects dealing with "what if" resulting in over architected crap where if never happened. – Ladislav Mrnka Aug 12 '11 at 20:55
  • @Taesung Shin, if using IDbSet and a subclass of DbContext providing a generic `ISomethingContext` Interface, and only referencing those interface throughout the code, then you *are* IMHO in fact applying the repository pattern and should be able to switch to SQL CE or NHibernate by reimplementing your `ISomethingContext` interface. Do I miss anything? – chiccodoro Aug 18 '11 at 09:08
  • @Ladislav I asked the question as a learner to an expert so I think you don't have to be that defensive. Maybe my tone was not enough to be polite - sorry I am foreigner. You are right that we should do only what we are paid to do. In my opinion, however, repository seems to be simple to implement and simplify fat interfaces of dbcontext and dbset with extensibility. So we lose two principles of OODP (Open-close and interface segregation) without repository. Yeah yeah, still we need to do what's paid. – Tae-Sung Shin Aug 18 '11 at 13:39
  • @chiccodoro Thanks for your comment. Please see my comment above. – Tae-Sung Shin Aug 18 '11 at 13:42
  • It sounds like most of your points might vary depending on how the repository pattern was implemented. – Didier A. Feb 26 '14 at 15:41
4

I would use the Repository Pattern. Here is an example using EF code first and MVC Entity Framework 4 CTP 4 / CTP 5 Generic Repository Pattern and Unit Testable

Here are some good reads on the pattern:

It may also be a good idea to look into Domain Driven Design (DDD) since you are starting with a Domain Model.

Some good reads on DDD:

Community
  • 1
  • 1
Paul
  • 12,146
  • 4
  • 45
  • 56
2

If you use EF directly in business methods (Domain Layer Services & Application Layer Services) then you are not isolating the Domain Model Layer from the infrastructure technologies (EF in this case). That is one of the DDD principles. you should probably have one Repository per Aggregate.

For more info about DDD, see:

Eric Evans' book: http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215

Microsoft: http://msdn.microsoft.com/es-es/architecture/en

Cesar
  • 21
  • 1