6

I am trying to use EF6 with my project. I just watched Repository Pattern with C# and Entity Framework, Done Right | Mosh video. I understand the necessity of Repositories but I still don't understand UnitOfWork. I already have my DBContext to use instead of UnitOfWork. In the sample code of the video it is like:

using(var UnitOfWork = new UnitOfWork(new DBContext()))
{
    UnitOfWork.Courses.Get(1);
}

I don't understand the benefit of this. I can just directly use my dbContext in all of my repos,

using(var dbContext = new DBContext())
{
    var courseRepo = new CourseRepo(dbContext);
    var otherRepo = new OtherRepo(dbContext);

    courseRepo.Get(1);
}

So my repositories will be using the same dbContext. What is the reason of UnitOfWork then?

6
  • 4
    In general, people like to show of "Patterns" in their tutorials to show how much they know about patterns. You will find thousands of articles using patterns "just because". Look inside the class or pattern what it actually does. You will find that in this case it probably does nothing because EF already does all that by itself.
    – nvoigt
    Mar 19, 2020 at 6:52
  • the key thing here is whether you have a repo per table or per database. the UoW gives you a transaction scope decoupled from your repos.
    – Ewan
    Mar 19, 2020 at 7:32
  • I have repo per table.
    – Mansur
    Mar 19, 2020 at 7:34
  • @Ewan: Since the context is managed outside of the repositories (and manually injected into them), that transaction scope is already achieved by handling the context itself. Your comment is not wrong but it doesn't quite apply to OP's specific situation as OP is focused on what a uow would add to what they already have.
    – Flater
    Mar 19, 2020 at 10:08
  • @Mansur that's generally considered an anti-pattern. But its the reason for the UoW pattern. despite what Flater suggests, you don't really have an external transaction. Nothing forces both repos to use the same context, (or even in edge case not do stuff outside its implicit transaction)
    – Ewan
    Mar 19, 2020 at 10:43

3 Answers 3

22

The Entity Framework DbContext is a unit of work, and its DbSet<T> properties are repositories.
That's not to say that you should never roll your own layer on top of them, but you're correct in asserting that the db context, in the way you're using it, precludes the main goal of a unit of work.

Your situation is quite unique in that you manually inject your context into your repositories, which gives you (the consumer of the repositories, i.e. whichever class contains the using block) direct control over the context and when it is committed.

That's not the case for a lot of other codebases, where the repositories conceal the EF dependencies and thus don't allow the context to be used outside of the repo. That leads to an inability to control the context on a layer above the repositories, which makes it hard to direct a transaction that spans multiple repositories.

In such a case, a custom built unit of work makes sense, as it give the consumer indirect control over the db context via the unit of work.

In short, in an Entity Framework context, a unit of work should only be used as an non-EF-dependent interface on top of your EF context.


To summarize, I want to address your actual question and the question I think you were actually asking about:

Is unit of work pattern really needed with repository pattern?

Yes, as it orchestrates atomic data operations that span more than one repository. Think of a unit of work as the director (uow) of an orchestra (repositories).

Is unit of work pattern really needed with Entity Framework?

Not necessarily. EF already provides the unit of work pattern for you. The only reason to still have a unit of work is if you:

  • want to include non-EF-datasources in an atomic data operation.
  • want to use a unit of work in your domain without relying on an EF dependency on that layer.
  • need a unit of work with a richer feature set than what EF provides - though this can in some cases still be done by extending the db context rather than wrapping it.

Not a direct answer to your question but tangentially relevant, I've written a lengthy answer on the benefits of units of work and repositories in conjunction with Entity Framework. It may be an interesting read for you as you're dealing with the same subject matter.

11

The Unit-Of-Work pattern makes sense when you have a complex use case with several objects involved, often objects which map to different master-detail tables. As part of the use case, you want to

  1. pull all the required objects out of the database

  2. let the user edit these objects (his local copy), until they are satisfied with the result. "Edit" here may mean to add or remove new "detail objects", or undo and redo certain steps.

  3. Finally, write the result set of objects back to the database in one transaction (or give the user the opportunity not to write the changes back, in which case nothing is changed in the DB).

For example, such a use case could be the creation of an order for an online shop (with several items involved, an ordering adress, a billing adress, a method of payment etc). Or it could be the editing of a complex structural component for a software supporting the construction of buildings. Or it could be the editing of an insurance contract, where the contract is not just a single-record document, but split-up into several objects with a lot of meta data.

For all these case, it makes sense to have a coordinating object which keeps the related data together and tracks the changes to the involved objects, so they can be written back to the database "at a whole", in a transactional and optimized fashion. That is what the Unit-Of-Work object is for. Steps 1 and 3 will usually make use of repositories.

Of course, when an ORM like EF supports automatic change tracking, for use cases which can fully rely on that in-built mechanism, an UoW may not be necessary. But "interesting", real-world requirements are not always that simple: EF's automatism may not be sufficient or not performant enough, or there are other systems or technologies or layers to be included.

So the UoW is just an extra layer between the repositories and a certain service or use case implementation, designed for the specific use case's needs. It is definitely not necessary for use cases like trivial CRUD operations on a single DB table, or use cases which are only slightly more complex, like the simplistic examples shown in the question.

9
  • Yes I understand the concept of using more than one DB tables (entities) and tracking all of them with a single source. That's why I came up with my second code block. Isn't it the same? If it is the same, if I can reach the same goal without using UOW why should I use it? In the second code block I also use more than one entities and I can save changes with the shared DBContext. So I think it will produce the same result with UOW. So there are two questions. 1- Am I incorrect, Doesn't the second code block yield the same result with UOW. 2- If it is the same what is the extra benefit of UOW.
    – Mansur
    Mar 19, 2020 at 6:43
  • Can you explain why one needs an additional unit-of-work pattern when entity Framework context already implements the very behaviors you describe?
    – nvoigt
    Mar 19, 2020 at 6:44
  • @Mansur: in which class do you want to place your "second code block"?
    – Doc Brown
    Mar 19, 2020 at 7:02
  • 1
    @nvoigt: ok, I added a few words. To what you wrote about "people" here: the idea should be that one starts to implement a certain use case, and when the transactional handling of the objects involved becomes obviously too complex, then it is time to refactor the complexity into a separate layer like the UoW. The UoW is not for people who work like braindead zombies and try to throw patterns at a system "just in case" - one has to see the problem in code first, and then solve it, not the other way round.
    – Doc Brown
    Mar 19, 2020 at 8:16
  • 2
    @DocBrown I absolutely agree with that.
    – nvoigt
    Mar 19, 2020 at 8:20
1

I think there is one other aspect to consider, regardless of what has been brought up earlier, and that is the matter of decoupling technology (Entity Framework / EF Core via the DbContext) from business code.

This is generally desierable, but how this is obtained for each specific real world scenario are discussions better suited some place else. However, one way to achieve this breaking of dependancies would be to contain the DbContext (being a Unit of Work in itself) inside another class. How to do this is of course a matter of taste, but I feel as if this perspective should be represented alongside the other ones previously provided.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.