Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Wednesday, January 26, 2011 8:48 AM
Hello,
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.
All replies (11)
Thursday, January 27, 2011 12:39 PM âś…Answered
You say : "There isn't anything to return, if meet_request can't be created in an invalid state so nothing can go wrong after the meeting request has been submitted, apart from db failure."
I create the MeetingRuest in a valid state so there is no reason to think that it will not be persisted.
public class NewMeetingRequest
{
public string person_to_meet_with { get; private set; }
public string location { get; private set; }
public DateTime date { get; private set; }
public NewMeetingRequest(string person_to_meet_with,
string location, DateTime date)
{
// validate parameters
this.person_to_meet_with = person_to_meet_with;
this.location = location;
this.date = date;
}
}
Remember that I was only using an example, you could have the method return anything like..
public Meeting Handle(NewMeetingRequest meeting_request)
{
////
return meeting_request;
}
Wednesday, January 26, 2011 9:15 AM
second
THe least dependencies, the better
Wednesday, January 26, 2011 9:25 AM
IMO the unit of work is related to business cases and so should be owned by the business logic, I something like so:
public class ABusinessCase
{
private IUnitOfWorkFactory _unit_of_work_factory;
private IRespositoryA _repository_A;
private IRespositoryB _repository_B;
public ABusinessCase(IUnitOfWorkFactory unitOfWorkFactory,
IRespositoryA repositoryA, IRespositoryB repositoryB)
{
_unit_of_work_factory = unitOfWorkFactory;
_repository_B = repositoryB;
_repository_A = repositoryA;
}
public void Handle(RequestForBusinessCase request)
{
using (var unit_of_work = _unit_of_work_factory.create())
{
// Do business work...
_repository_B.Add(entity_created_from_business_case);
_repository_A.Save(entity_modified_from_business_case);
}
}
}
The unit of work implementation (EF) which implements IDisposable will submit the changes within a transaction on the dispose method.
Cheers
Scott
Wednesday, January 26, 2011 9:36 AM
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.
Wednesday, January 26, 2011 9:42 AM
IMO the unit of work is related to business cases and so should be owned by the business logic, I something like so:
public class ABusinessCase
{
private IUnitOfWorkFactory _unit_of_work_factory;
private IRespositoryA _repository_A;
private IRespositoryB _repository_B;
public ABusinessCase(IUnitOfWorkFactory unitOfWorkFactory,
IRespositoryA repositoryA, IRespositoryB repositoryB)
{
_unit_of_work_factory = unitOfWorkFactory;
_repository_B = repositoryB;
_repository_A = repositoryA;
}
public void Handle(RequestForBusinessCase request)
{
using (var unit_of_work = _unit_of_work_factory.create())
{
// Do business work...
_repository_B.Add(entity_created_from_business_case);
_repository_A.Save(entity_modified_from_business_case);
}
}
}
The unit of work implementation (EF) which implements IDisposable will submit the changes within a transaction on the dispose method.
Cheers
Scott
Sorry i am not fully understand, actually that the first time i see this implementation it is some kind of other layer ? Could you clarify a bit ? it seem not everyone go in the same direction for implementing the Unit of work. Ive heard in a lots of place that business work should be done in the service layer.
Thanks.
Wednesday, January 26, 2011 9:43 AM
IMO the unit of work is related to business cases and so should be owned by the business logic, I something like so:
public class ABusinessCase
{
private IUnitOfWorkFactory _unit_of_work_factory;
private IRespositoryA _repository_A;
private IRespositoryB _repository_B;
public ABusinessCase(IUnitOfWorkFactory unitOfWorkFactory,
IRespositoryA repositoryA, IRespositoryB repositoryB)
{
_unit_of_work_factory = unitOfWorkFactory;
_repository_B = repositoryB;
_repository_A = repositoryA;
}
public void Handle(RequestForBusinessCase request)
{
using (var unit_of_work = _unit_of_work_factory.create())
{
// Do business work...
_repository_B.Add(entity_created_from_business_case);
_repository_A.Save(entity_modified_from_business_case);
}
}
}
The unit of work implementation (EF) which implements IDisposable will submit the changes within a transaction on the dispose method.
Cheers
Scott
Sorry i am not fully understand, actually that the first time i see this implementation it is some kind of other layer ? Could you clarify a bit ? it seem not everyone go in the same direction for implementing the Unit of work. Ive heard in a lots of place that business work should be done in the service layer.
Thanks.
Wednesday, January 26, 2011 10:09 AM
Maybe if I put it into context...
This is within the Service/Business/Domain whatever you want to call it layer. Its the layer which contains the business logic. I often call this the Domain layer as I typically use it to store entities/services/workflow/values that represent the business domain.
namespace MeetingApplication.Domain
{
public class AddMeetingRequestService
{
private IUnitOfWorkFactory _unit_of_work_factory;
private IPersonRespository _person_repository;
private IMeetingRespository _meeting_repository;
public AddMeetingRequestService(IUnitOfWorkFactory unitOfWorkFactory,
IPersonRespository person_repository,
IMeetingRespositorB meeting_repository)
{
_unit_of_work_factory = unitOfWorkFactory;
_person_repository = person_repository;
_meeting_repository = meeting_repository;
}
public void Handle(NewMeetingRequest meeting_request)
{
using (var unit_of_work = _unit_of_work_factory.create())
{
_person_repository.Add(meeting_request.person_to_meet_with);
_meeting_repository.Add(meeting_request.meeting_details);
}
}
}
}
Does that make more sense?
Wednesday, January 26, 2011 10:28 AM
Alright, i understand more but this look a bit different from my point of view.
To me it look like a service which have access to an instance of an unit of work, apparently a single instane since you use a UoW factory. It also have access to two repositories.. (however shouldnt the meeting INCLUDE the numbers of persons and act as an aggregate root ? if yes then there shouldnt be a personrepository but only a meetingrepository). The unit of work then seem to be handled in the request, then it do business work and then use an instance of UoW to do his saving operations and flush it. And this actual service is called by the controller.
I would call it MeetingService and i would put a method that actually call the AddMeetingRequest.
About Handle i am not sure where this is called ? umm probably in controller. The controller build up the request and call handle with that request. That probably why you didnt used a method called AddMeetingRequest but prefer using the AddMeetingRequest as a service class to be sure it do and handle one concern.
Also your saying it contain the business logic.. but where ? it is in the request object? it is in the handle before adding to the repository ? if i am right it should be in the handle method.
One more thing that is obscur is the request.. what it actually do.. from what i see it seem to contains some informations about the case. But if the handle is called from controller shouldnt it return some viewmodel (if there any?)
I am wrong ? correct me if so. After all its like saying repository and unit of work go in service layer but using a brillant way to do it.
Wednesday, January 26, 2011 12:13 PM
(however shouldnt the meeting INCLUDE the numbers of persons and act as an aggregate root ? if yes then there shouldnt be a personrepository but only a meetingrepository)
Don't pay too much attention to the context, I couldn't think of a good example. Just assume that this business action results in the persistnce of entities relating to two different aggregates.
I would call it MeetingService and i would put a method that actually call the AddMeetingRequest.
Again this is just how my own convention. Yes I have one class for one business concern.
One more thing that is obscur is the request.. what it actually do.. from what i see it seem to contains some informations about the case. But if the handle is called from controller shouldnt it return some viewmodel (if there any?)
Again this is just an example, it does do anything I just made it up :0) The business logic would be in the area where I added the coment // Do business work in the original comment post. There isn't anything to return, if meet_request can't be created in an invalid state so nothing can go wrong after the meeting request has been submitted, apart from db failure.
I will write some made up logic...
e.g.
public void Handle(NewMeetingRequest meeting_request)
{
using (var unit_of_work = _unit_of_work_factory.create())
{
Person person_to_meet_with;
Meeting meeting_details;
if (!_person_repository.Contains(new Query<Person>(p => p.full_name == meeting_request.person_to_meet_with.full_name)))
{
person_to_meet_with = new Person() { full_name = meeting_request.person_to_meet_with.full_name};
_person_repository.Add(person_to_meet_with);
}
else
{
person_to_meet_with = _person_repository.Contains(
new Query<Person>(p => p.full_name == meeting_request.person_to_meet_with.full_name);
if (person_to_meet_with.has_meeting_that_will_clash_with(meeting_request))
// Send notification of possible clash event .....
}
meeting_details = new Meeting() {person_to_meet = person_to_meet_with,
where_to_meet = meeting_request.location,
when_to_meet = meeting_request.date}
_meeting_repository.Add(meeting_details);
}
}
Make sense?
Wednesday, January 26, 2011 12:32 PM
Alright, yes that all make sense but one more thing about the final point which i don't fully understand.
You say : "There isn't anything to return, if meet_request can't be created in an invalid state so nothing can go wrong after the meeting request has been submitted, apart from db failure."
Do you mean that if the controller couldn't create the meeting_request object (because of an invalide state from the request) then there nothing to return and nothing will go wrong since it never created it. That actually mean that Handle will only be called IF the state is valid.
That said, if i ever success in creating a meeting_request and want to show the details, i will simply build up a viewmodel based on the request details from the meeting_request object ?
But what if i need to do some calculation in the service and return his result in a view ? (as an example) I understand that this is a one-way service but is there two way services possible (such as my example) ?
Also, how this is called from the controller ? this doesnt seem to be an interface you can bind to any controller. The only way i could see is that you make an interface which implement each methods relative to business cases then you create a class from it that call handle for each business case.
Thanks a lots for helping ! I know you might be busy but i just trying to understand :-)
Thursday, January 27, 2011 1:18 PM
Alright, thanks you a lots ! :-)