简体   繁体   中英

UOW and Repository Pattern in EF5

This is about some confusion I have about some of the entity framework material I have found from here: https://www.asp.net/

On this Page it explains how to wrap a dbcontext using a repository and to wrap a repository using aa unit of work class: http://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

However, on this page it states that a dbcontext is already a combination of both the UOW pattern and the repository pattern: https://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext(v=vs.103).aspx

So if the problem that these patterns solve are already solved by dbcontext, why re-implement these patterns with EF5?

Also, in the tutorial, the UnitOfWork class doesn't seem to show any benefit that UOW is supposed to give. for instance it states: "That way, when a unit of work is complete you can call the SaveChanges method on that instance of the context and be assured that all related changes will be coordinated. "

but all it seems to do is wrap the dbcontext for no reason. I think I am missing something. I don't see any co-ordination in this implementation... And how do thing "rollback" if something goes wrong?

Don't use another UoW/repository abstraction layer

As OP correctly pointed out, Entity Framework (similar to eg NHibernate and other ORMs) already provide an abstraction of the database for you with both a transactional "unit of work" and "repositories" that are available to you.

The extra UoW / repository abstraction layer is an anti-pattern , that should be avoided at all cost. There are numerous problems with it, the most important of them being:

  • they prevent you from using the full power of the underlying ORM (lazy load, eager load, complex queries, ....)
  • if they want to provide any added benefits beyond simple CRUD, they will be leaky (ie reflect the capabilities present in the underlying ORM).

But, but, but ...

I need to be able to unit test by mocking my repositories

No, you don't. Just use a database with content specific for your test for that. Use an in-memory database (eg SQLite, Effort , ...) if you want this to be faster.

EF does not enforce business logic which is not expressed in data relationships ... To enforce this type of logic, you have to build a OUW/Repository/both of some sort around the EF context.

No, you should't. To implement your business logic in an infrastructure abstraction layer such as a unit of work or repository is just plain wrong.

  • Valuable business logic belongs in domain entities, domain services, domain commands or for long running business processes, sagas.
  • Simple validations (ie not null , value between x and y ) don't: those should be solved at your system interface boundaries.

Also note that simple CRUD style actions without any valuable business logic don't need to go through all the "layer hoops", ie avoid this pattern:

  1. Database → Entity without behavior → DTO → View Model → View
  2. Edit fields
  3. View → View Model → DTO → Entity without behavior → Database

Just load it directly from your ORM in your controller in the "View Model" shape needed for the view, and save it directly from your controller.

On abstractions

Unnecessary abstractions and layer hoops such as these are evil. They obfuscate your code, tie your hands, leak, increase your code size and therefore the amount of bugs in your code without providing any added value.

Use abstractions when they offer you added value, eg when you need them in solving cross-cutting concerns, capturing/managing recurring patterns in your architecture, ...

Creating abstractions for the sake of abstracting is a waste of time.

I've already written extensively on this here , but I'll summarize for your benefit. Yes, Entity Framework already implements the UoW ( DbContext ) and repository ( DbSet ) patterns. There is no benefit in re-implementing them yet again. In fact, there's great detriment as it adds significantly to the maintenance overhead of your project.

Why did Microsoft include this in the introductory tutorials? Honestly, I'm not sure, but it was a mistake that has plagued countless new MVC developers, myself included when I was just getting started.

There is benefit in some sort of abstraction, such that your project is not dependent on any one particular way of getting data. However, this abstraction should return the specific data that your actions need, no more, no less. For lack of a better word, I refer to this as a "service", although Microsoft has grafted quite a different meaning onto that word via SOA. Simply, it's like you're just creating an API for your application to use, much as if you were creating a web API, only entirely code-based (not requiring an actual HTTP connection). This then goes into your DAL layer (class library or similar) that your project can reference.

The thing about EF is that there is no business logic in the OUW or Repository functionality it exposes. If you call SaveChanges it will happily save all changes. However, it there is a requirement that when adding say a Widget the addition of a Frobber for the Widget is necessary you are out of luck (unless there is a FK dependency involved). For any bit of business logic which is not expressed in data relationships, EF out of the box does not enforce it.

To enforce this type of logic, you have to build a OUW/Repository/both of some sort around the EF context. That's the only reason you'd do it to my knowledge.

unit of work and repository pattern has no concern with entity frame work. it is one of the design pattern. so it is used to make your code more readable, re-usable and efficient and also these pattern are used to achieve singelton (one time object instanciation) and also for avoid inversion of control.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM