w0051977
w0051977

Reputation: 15807

How is Change Tracking an issue when separating the Domain Model and Persistence Model?

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

Answers (3)

Amit Joshi
Amit Joshi

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

Sylvain Lecoy
Sylvain Lecoy

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.

https://github.com/VaughnVernon/IDDD_Samples_NET/tree/master/iddd_identityaccess/Domain.Model/Identity

Upvotes: 1

MikeSW
MikeSW

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

Related Questions