2

I'm currently working on a web app which consist of 6 layers:

  • Web (reference to ViewModels and Controllers)
  • ViewModels
  • Controllers
  • Services (reference to Data and Entities)
  • Data (reference to Entities)
  • Entities

What I'm trying to is to implement a "UnitOfWork" pattern, and therefore I have a class thats injected by DI for that job which makes it possible to do .commit() in the actionresult in the controller when I'm done with the database.

Now is my question... Where should this UnitOfWork class be placed? It's at the moment in my Data layer but that requires the Controller layer to reference the Data layer AND the Service layer, which is odd in my opinion... Should I move the UnitOfWork class/interface to the Service layer and use DI?

ebb
  • 9,297
  • 18
  • 72
  • 123

3 Answers3

5

Unless you're using the Repository pattern in your Data layer, you're wasting your time.

The point of a UoW is to handle changes across multiple Repository instances, this is done in the following ways:

  1. Unit of Work derives from the actual underlying context (DataContext - L2SQL, ObjectContext/EF)
  2. Repositories take a Unit of Work in their ctor.

The Unit of Work do two things:

  1. Have a Commit() method
  2. Expose the underlying object/entity set to the Repository.

It's a little tricky to get it all setup, but once you do, the flow should be like this:

  1. Controller get's DI'ed a service and a unit of work (both via Interfaces)
  2. Controller calls method on a service ("CustomerServices.AddOrder()")
  3. Service calls method on Repository
  4. Repository calls "Add" method on "Order" object/entity set
  5. Controller commits Unit of Work

Essentially, each layer takes an instance of the "next layer" in their constructor. Everything should be DI'ed and interface-driven. The UoW has not reliance on anything - but the Repository relies on it for persistence to the "internal memory" (ORM), then the UoW "Commit" will push the changes out to the database (basically wraps the "SaveChanges" method).

As the Unit of Work is an infrastructure/persistence/database/transactional concern, it should go into your Data layer. Should only be referenced by Controllers.

halfer
  • 19,824
  • 17
  • 99
  • 186
RPM1984
  • 72,246
  • 58
  • 225
  • 350
  • Exactly! - thats how it works... But I'm just wondering WHERE to place the IUnitOfWork (which layer?) – ebb Feb 08 '11 at 21:01
  • @ebb - data layer. it's an infrastructure/data concern. – RPM1984 Feb 08 '11 at 21:02
  • @RPM1984 - But that would make my Controller layer reference both the Service AND Data layer? – ebb Feb 08 '11 at 21:05
  • @ebb - actually i take that back. My UoW is in a "Common" assembly. Things like common LINQ extension methods, the generic repository interface/abstract class, and the Unit of Work interface. So your Controller references the "Common" assembly, and the implementation is contained in your "Data" assembly - which is configured via DI. If that makes sense. – RPM1984 Feb 08 '11 at 22:23
  • It does... but having the generic repository interface as a part of the "common" assembly - isnt that too much, since its only related to the Service layer? - I do see that it would be a good idea to give the UoW its own assembly, but then again... having a "Common" assembly with things that only should be used in 1 layer (and the one where its declared) - is "over seperating" in my mind. – ebb Feb 08 '11 at 22:45
  • @ebb - by "Common" i mean it can be used by **multiple applications**, not **multiple layers**. The Repository is not tied to a service, that's the key. Consumers (applications) can choose to hook straight into the Repository via the UI, or go through their own custom service layer. – RPM1984 Feb 08 '11 at 23:49
  • @RPM1984 - I see... so I should throw all my stuff that "can" be reused into a "Common" assembly - and that way I'll also be able to use the IUnitOfWork in the Service layer without referencing the Data layer? – ebb Feb 09 '11 at 09:19
  • @ebb - you mean "i'll also able to use the IUnitOfWork in my **Controllers** without referenceing the data layer. then yes. – RPM1984 Feb 09 '11 at 21:18
  • @RPM1984 - But isnt that "overdesign" - since you are dedicating a whole assembly for just one class? – ebb Feb 10 '11 at 19:44
  • @ebb - we could go on about this for days. :) It's a matter of preference. The "Common" assembly has a LOT of common code. Not just UoW/Repo. – RPM1984 Feb 10 '11 at 20:39
  • @RPM1984 - Do you have simple example of this? Maybe show the constructors per layer and then the implementation in the controller. Maybe the interface signatures as well? - Thanks! – Sam Mar 03 '11 at 05:50
0

I implemented my IUnitOfWork class to be passed directly into my MVC controllers (injected via Castle Windsor). I then have my controller pass it to any service objects it instantiates.

KallDrexx
  • 27,229
  • 33
  • 143
  • 254
0

IUnitOfWork should be an interface for data layer. When request come into Controller then call service methods, if you require CRUD there should call UnitOfWork. You may use Session Per Request by call UnitOfWork in Global.asax Request_Start and commit works in Request_End.

  • 1
    But the whole point of UnitOfWork is to make it independent of the Service layer. The Service should only be aware of the Data layer. So service = add/delete/update, ActionResult in controller = .commit() to flush all the operations at once to reduce number of trips to database. – ebb Feb 08 '11 at 20:50
  • Your Service layer do not depend on UnitOfWork but should depend on Interface Layer which contains the IUnitOfWork – John Geng Feb 08 '11 at 21:16