6

Just wondering, in an ASP.NET MVC3 environnement with entity framework. Should the Unit of Work point to the service layer or the repository (and then the repository point to the service layer) ?

Ive saw two example:

  • One where the unit of work and repository both have an instance to the service layer..

Link: Entity Framework 4 CTP 4 / CTP 5 Generic Repository Pattern and Unit Testable

Doesn't use a service layer but its obvious that one could be use in that case.

  • Second where the unit of work have an instance to the repository which have an instance to the service layer..

Link: http://blogs.msdn.com/b/adonet/archive/2009/06/16/using-repository-and-unit- of-work-patterns-with-entity-framework-4-0.aspx

What would be better ?

Thanks.

Community
  • 1
  • 1
Rushino
  • 9,415
  • 16
  • 53
  • 93

2 Answers2

6

Well actually, if you think about it, the Controllers should work with the Unit of Work.

Typically in an ASP.NET MVC application, a Controller is assigned a new unit of work when a HTTP Request comes in.

The Controller will then call methods on the service (which calls methods on the Repository), fetching and making changes to the Entity Framework internal graph/memory.

Once the Controller has done what it needs to do, it will perform a "Commit" on the Unit of Work, which results in any changes to the underlying repository being commited to the database.

I assume when you talk about a "Service", you have a intermediary layer between your Controller and Repository, where the Controller only talks to the Service, the Service then talks to the Repository, then back up the app stack.

So your Controller might look like this:

public class ProductsController : Controller
{
   private IUnitOfWork _unitOfWork;
   private IProductsService _service;

   public ProductsController(IUnitOfWork unitOfWork, IProductsService service)
   {
      // use dependency injection here
      _unitOfWork = unitOfWork;
      _service = service;
   }

   [HttpPost]
   public ActionResult SubmitOrder(Product p)
   {
      var existingProduct = _service.FindById(p.ProductId);
      UpdateModel(existingProduct);
      _unitOfWork.Commit();
   }
} 

In most EF4 scenarios, the Unit of Work is implemented as a wrapper for the ObjectContext. In other words, the "Commit" method on your Unit of Work would simply perform "SaveChanges" on the ObjectContext.

Therefore, the Unit of Work doesn't really point to either the service or the repository. It simply works with the persistence mechanism that is manages.

RPM1984
  • 72,246
  • 58
  • 225
  • 350
  • 1
    The only problem I see with this is that controllers are generally tightly bound to a particular view (e.g. browser versus desktop). So if you change views you have to recode all your transactional logic? And what if you want to expose services in a service-oriented architecture without thinking about any UI or controller? Do those services not care about transactions? I think it should be more about SOA and less about UI. – duffymo Jan 26 '11 at 10:22
  • Not bad, in facts i love both answer. However, im still unsure of the right path to go. @RPM1984 your right saying that the unit of work should work simply with the persistence mechanism since that his goal but duffymo is not wrong saying that if you want to expose the services without an UI or controller.. you lost that mechanism since its included in the controller. Seem uneasy to answer this kind of question.. would it depend on the architecture ? Ive also seen some place where repository is set in the unit of work. – Rushino Jan 26 '11 at 13:00
  • While reading some others questions and post, some tend to say that the controller should not know about the Unit of work since this would violate the Single responsbility principle. Even the service shouldnt know about it. In fact they say that it should be hanlded in application_startrequest and application_endrequest. What do you think about this ? – Rushino Jan 26 '11 at 13:34
  • And yes i agree with duffmo about services/SOA. However, this is an ASP.NET MVC application, i just answered the specific scenario. Are you planning to move to an SOA architecture? If not, then it's kind of a moot point. – RPM1984 Jan 26 '11 at 20:59
  • @duffmo - also, you don't **have** to put the transactional logic in the action method. You could use action filters in a base controller. For example you could commit the UoW in the OnResultExecuting event. – RPM1984 Jan 26 '11 at 21:02
  • @RPM1984 i think i will put it in the service layer or the repository. But thanks for your answers. – Rushino Jan 26 '11 at 21:09
  • @Rushino - no problems. Just thought id offer an alternative (and how i currently use UoW in my MVC application). – RPM1984 Jan 26 '11 at 22:24
  • It sounds like a lot of this comes down to the implementation of each `ActionMethod` - what is going on when you make a particular request to the site. If an `ActionMethod` is calling 2 different services, then two UoW will be constructed (using @DuffyMo's idea). I'm guessing he'll then add: you shouldn't be calling 2 different services per request. These should be aggregated to a single service to isolate the logic. Using DI, most of the examples are showing using Constructor Injection .. and this is when the controller is constructed .. which is why the UoW is created at that point. Hmm.... – Pure.Krome Jan 26 '11 at 23:02
  • @Pure.Krome: From what i understand, you shouldn't be calling two service and anyway you can't (cause you bind one service to your controller normally). That service is supposed to fullfil all the requests for the specific controller. Also the UoW should be created and then dropped after a request and this is probably done in each of the service methods. – Rushino Jan 26 '11 at 23:21
4

I'm not sure what you mean by "point to", but I think transactions are the responsibility of the service layer, not persistence.

A persistence object can't know if it's part of a larger unit of work. The responsible service has references to all the model and persistence objects that make up the unit of work. The service is responsible for managing connections from the pool on behalf of the persistence objects as well. Obtain the connection, open the transaction, perform the work, either commit or rollback the transaction, and close the connection. That's the service's job.

duffymo
  • 305,152
  • 44
  • 369
  • 561
  • "point to" is probably not the best word. I meant the service layer access an instance of UoW and Repository. So "point to" mean "access an instance of". Anyway, so basically you mean that the service layer should have an instance of the unit of work (to do transactions) and the repository ? – Rushino Jan 26 '11 at 02:49
  • 1
    Thanks for the explanation. Yes, the transactions should be associated with services, which use repositories and model objects to fulfill use cases. – duffymo Jan 26 '11 at 10:20
  • Just for clarification, i figured that my question was a bit obscur. The Unit of Work AND repository could both be in the service layer ? or you mean Unit of work be in repository which be in service layer ? Thanks. – Rushino Jan 26 '11 at 14:36
  • No, I mean unit of work in the service method scope and repository/repositories owned by the service. If you put transaction on repository, what happens if there's more than one repository? That's why it has to belong to the owner of the repositories - the service. – duffymo Jan 26 '11 at 17:01
  • @DuffyMo - how would you use DI with creating a UoW in your Service app? Property Injection? – Pure.Krome Jan 26 '11 at 23:06
  • @duffymo : You right. So Unit of Work at the service level with repository or repositories owned by that service. Great! Thanks you a lots! – Rushino Jan 26 '11 at 23:12
  • @Pure.Krome : i never tried perperty injection but i recommand constructor injection, that seem the perfect choice with HttpRequestContext scope for the binding. – Rushino Jan 26 '11 at 23:14
  • Transactions are a natural choice for aspect oriented programming. I would write an aspect and weave it in as advice on all service interfaces. Services need to have their dependent repositories injected in, of course. I prefer constructor injection, too. – duffymo Jan 26 '11 at 23:40
  • It seem that EF support transaction internally (see Contexte.Connection.BeginTransaction) which enable to do commit and rollback too. – Rushino Jan 27 '11 at 00:15
  • I'm not saying it can't be done with a DAO or repository; I'm arguing that it shouldn't be. If you'd prefer to have repositories own transactions, please do so. – duffymo Jan 27 '11 at 00:41
  • It's possible to demark units of work in Java or Hibernate using the equivalent of BeginTransaction and doing commit or rollback in code, but I think it's a cleaner design to do this in aspects that advise the service layer. You can do it whatever way you're comfortable. You'll be duplicating that code in every controller that needs transactions. Your maintenance burden will be greater. Your choice. – duffymo Jan 27 '11 at 00:55
  • I never said i would put them in repositories, after what you said i would never because its make sense. I was just pointing out the fact that EF can do transactions. Ive put them in service where it belong. – Rushino Jan 27 '11 at 11:24