Reputation: 15807
I was reading this question here: Having Separate Domain Model and Persistence Model in DDD
and specifically looking at this code:
public class ApplicationService
{
private ITicketsRepository ticketsRepository;
public ApplicationService(ITicketsRepository ticketsRepository)
{
this.ticketsRepository = ticketsRepository;
}
public bool IsTicketExpired(int ticketId)
{
Ticket persistanceModel = this.ticketsRepository.GetById(ticketId);
TicketEntity domainModel = new TicketEntity(
persistanceModel.Id,
persistanceModel.Cost,
persistanceModel.ExpiryDate);
return domainModel.IsTicketExpired();
}
}
This code means there is a separate Domain Model and Persistence Model. I am trying to understand what the limitations of using this approach are. All over the Internet I read about change tracking being an issue when using NHibernate, however I do not understand why. Change Tracking is dealt with after the domain model is mapped back to the persistence model. How is change tracking an issue? A practical example of how change tracking is an issue would help me.
Update Please see the code below:
//Repository
public Ticket GetTicket(int ticketId)
{
return this.ticketsRepository.GetById(ticketId);
}
and I do this in the application service:
//Application Service
Ticket ticket = applicationService.GetTicket(1);
ticket.Cost = .....
TicketEntity ticketEntity = AutoMapper.Map<TicketEntity>(ticket);
ticketEntity.DomainMethod();
ticket = AutoMapper.Map<Ticket>(ticketEntity);
Q1) Are the benefits of an ORM lost in this code e.g. change tracking? Notice that the persistence object is returned from the repository and then is mapped to a domain object and then back to the same persistence object.
Q2) How does NHibernate track changes i.e. how does it know that Ticket(persistence object) is ticket 1 in the database. I guess it is not simply by the ID.
Upvotes: 1
Views: 1372
Reputation: 16389
Most of the details in answer from @MikeSW are correct; I only disagree with change tracking. My answer is more in terms of NHibernate than DDD.
Yes, change tracking will be an issue but it depends on how the ISession
is managed. Further, not only change tracking, it will also affect other features of NHibernate like Session Level Cache, Lazy Loading etc.
Let us assume that ISession
is managed on request level i.e. one ISession
per request. And all activities mentioned below are part of one single request.
public TicketEntity GetTicket(int ticketId)
{
Ticket persistanceModel = this.ticketsRepository.GetById(ticketId);
TicketEntity domainModel = new TicketEntity(
persistanceModel.Id,
persistanceModel.Cost,
persistanceModel.ExpiryDate);
return domainModel;
}
public void SaveTicket(TicketEntity ticketEntity)
{
Ticket ticket = //Here, you have to map TicketEntity to Ticket
this.ticketsRepository.Save(ticket);
}
Now, following is the code somewhere in application in same request:
TicketEntity ticketEntity = applicationService.GetTicket(1);
ticketEntity.Cost = .....
.....
.....
applicationService.SaveTicket(ticketEntity);
NHibernate have ability to track changes happen in Ticket
but that ability is not useful here. Ticket
is lost while returning from GetTicket
and new Ticket
is created while SaveTicket
. Change tracking feature of NHibernate is not used at all even though ISession
was at request level and was able to see the changes happen.
Following code (which bypasses domain models) will track the changes properly though:
public Ticket GetTicket(int ticketId)
{
return this.ticketsRepository.GetById(ticketId);
}
Following is how you get and modify Ticket
:
Ticket ticket = applicationService.GetTicket(1);
ticket.Cost = .....
.....
.....
Now, you do not call SaveTicket
; instead you Flush
the ISession
somewhere in your application where you detect the EndOfRequest.
In this scenario, change tracking of NHibernate tracks the changes done to Ticket
and flushes those automatically.
By translating persistence model to domain model, we bypass this ability of NHibernate because persistence model is never changed.
There are benefits and drawbacks of each approach. Refer this question.
Edit: (for your Update)
Q1): New code will take benefit of change tracking if same instance of persistence model is modified and visible to same ISession
. It will also take benefit of Session Level Cache in that case. While mapping with AutoMapper, NHibernate will load referenced entities if any those may not be needed. This depends on each use-case though.
Q2): Actually this should be a different question being too broad to answer in this answer. Anyway, refer this.
Upvotes: 1
Reputation: 1017
On a side note, I would not recommand to separate domain model classes from persistence objects.
You might want to see what Vaughn Vernon did for his application on DOT.NET
He is the author of the famous book Implementing Domain Driven Design (IDDD). A must read that I recommand to any developer serious about DDD.
Upvotes: 1
Reputation: 16348
Change tracking is no issue. The mingling of Domain with Persistence is. The 'domain model' is mainly some data structure easily mapped to a table. In many domains, you might deal 99% with data structures with some rules attached. In those cases, your Domain model will look pretty much identical to Persistence model.
But going up a bit, at a more abstract level, the Domain Model models primarily business behaviour with state (data) being just an artifact. Further more, it looks at things from the business point of view (functionality).
Persistence model is about stored state i.e data structured in such a way that's easily retrievable. For domains with complex functionality that involves many concepts and their specific models and use case specific business rules, the resulted Model is quite different from the Persisted state.
How an ORM tracks changes is just an implementation detail that has nothing to do with DDD, however if the domain is rich enough, the simplistic CRUD solution and especially the mindset of domain model = state+behaviour a.k.a classes becomes an obstacle. With or without the ORM.
For the apps where the Domain = 98% Persistence Models, there's no problem, you can use whatever ORM you want.
Upvotes: 2