EF6 and Onion architecture - database first and without Repository pattern
Asked Answered
C

1

1

I'm trying to put it all together for an new architecture for existing application. Existing application has a lot of business logic, so I thought that Onion architecture (or something like that - layered, decoupled) could be the right solution - http://jeffreypalermo.com/blog/the-onion-architecture-part-1/

All examples that I have seen use Repo/UoW (on top or ORM) pattern in Infrastructure layer (or DAL, or whatever the layer that actually connects to database is called). But I'm not sure that in my case Repo/UoW (on top of EF) is necessary, because:

  • EF6 can be nicely Unit Tested without Repo pattern with implementing Bounded DbContexts like this - http://msdn.microsoft.com/en-us/library/dn314429.aspx

  • Most Generic Repo examples tend to use leaky abstractions, because they expose methods that accept LINQ queries (like Expression> query)

  • Non-generic Repos tend to cause a lot of code

So here are a few questions:

1) Most examples use EF code first and POCO objects in Core layer, but I have to use database first and generate model. Can I use EF generated .edmx model in Core, or does this makes unnecessary coupling to data access? Is there a way to split EF generated classes (.cs files with Table fields) from EF generated data access code (context.tt files etc.)?

2) I'm planning to implement Service layer like this (with Bounded DbContext interfaces being passed as dependencies)

public class OrderService(IMyDbContext) { ... } 

This means, that instead of Repository Interfaces, there will be DbContext wrapper interfaces with DbSets. Unit testing could be done with mock IMyDbContext and mock IDataSet. Doesn't this beat the whole concept of abstracting away the database? Seems to me that this is enough for unit testing, but is this ok from architectural standpoint? Am I missing some great feature that Repo/UoW (on top of EF) pattern provides here?

3) Seems that one alternative for Repositories (although, not very popular) are Query Objects: http://www.wekeroad.com/2014/03/04/repositories-and-unitofwork-are-not-a-good-idea/

http://lostechies.com/jimmybogard/2012/10/08/favor-query-objects-over-repositories/

But I haven't really found any examples with Onion + Query Objects. Could this be reasonable choice for Repository interface layer? Placing Query interfaces there instead, and Query Implementations in Interface (Data Access) layer? Should I place all data access logic inside QueryObjects? If I use DbContext.Where queries directly in Coltroller/Service layer, does this create unnecessary coupling between Data Access and Business Logic?

Contreras answered 21/5, 2014 at 7:44 Comment(2)
Your question, although interesting and relevant, is far too broad for the StackOverflow Q&A format.Northeastwards
perhaps this Q is better suited at codereview.stackexchange.comLifton
B
3

@andree

I have a few comments that may add to this discussion. I appreciate this is an older thread but I think the discussion is still valuable.

Firstly, I would now recommend not going with EDMX files as all the future discussions for EF7 seem to indicate that EDMX will be dropped. Instead, from EF6.1 you can now generate a "code-first" style configuration from an existing database.

"Code-first" should probably be renamed to "fluent configuration"

Most Generic Repo examples tend to use leaky abstractions, because they expose methods that accept LINQ >queries (like Expression> query)

Non-generic Repos tend to cause a lot of code

I've generally found that it can be useful to be a little "leaky". We use repositories that share IQueryable so that it's easy to write quick queries - but anything that's used often get moved into the repository proper. Obviously this would make it harder to swap out the persistence layer with something else that can't give you IQueryable but in practice this has never happened to me.

My approach to the "Non-generic Repos tend to cause a lot of code" problem has been to use code generation with .tt templates. - tt templates generate a bunch of partial repository implementations and interfaces. - Then, add your own methods to this in your own partial files.

please take a look at this library:
http://www.sswdataonion.com
(disclaimer: I was one of the developers for this)
It contains tt templates to generate a repository and unit-of-work pattern.

Personally, If I was to write a truly agnostic "non-leaky" service layer I would probably just write it as a layer on top of a repository / Unit of work pattern.

Bloomer answered 12/11, 2014 at 0:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.