C# – Should Data Model Be Identical to Domain Model for Mapping?

cdomain-driven-design

Say I have a data model, which looks like this:

public class DataCustomer
{ 
    public virtual System.DateTime CreatedTime { get; set; }
    public virtual Guid Id { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string Surname { get; set; }
    public virtual string FaxNumber{ get; set; }
    public virtual System.DateTime DateOfBirth { get; set; }
    public virtual String Gender { get; set; }
    public virtual string UserID { get; set; }
    public virtual List<Offers> Offers { get; set; }
}

This class is mapped to NHibernate. Now say I have a Domain Model like this:

public class DomainCustomer
{ 
    private virtual Guid Id { get; set; }
    private virtual String Gender { get; set; }
    private virtual DateTime DateOfBirth { get; set; }
    public virtual List<Offers> Offers { get; set; }

    public DomainCustomer(Guid id, string gender, DateTime dateOfBirth)
    {
          Id=id;
          Gender=gender;
          DateOfBirth=dateOfBirth;
    }

    public void AssignOffers(IOfferCalculator offerCalculator, IList<Offers> offers)
    {
          //Assign the offers here
    }

}

Notice that the Data Model looks different to the Domain Model. I believe this is normal practice, however every example I look at online seems to show the Data Model being the same as the domain model.

Option 1

The advantage of them being identical is that mapping between the Domain Model and Data Model is very simple i.e. you can do this with AutoMapper:

DataCustomer dataCustomer = AutoMapper.Mapper.Map<DataCustomer>(domainCustomer);

Option 2

The advantage of them being different is that there is less data passed between the data model and domain model and vice versa. Also I think that it makes it slightly clearer i.e. a user/reader of my class knows what fields are needed by the domain model. With this approach; I would only map the members that have changed i.e. offers:

customerData.Offers = AutoMapper.Mapper.Map<string>(customerDomain.Offers);

Decision

Both options use a factory when mapping between CustomerData and CustomerDomain. The question is about the mapping between CustomerDomain and CustomerData using AutoMapper.

Which option is more expected if I am following the principle of least astonishment?

Best Answer

For the sake of simplicity, let us first assume your "data model" reflects the underlying persistence model, probably a relational model behind it. Then it depends heavily on the size and structure of the overall system how much the data model will be different from the domain model:

  • in small systems, there will be often only one core application. One starts with creating a small domain model, and the data model will be derived from it, solely for the purpose of persisting the domain model. In such a system, it is unlikely to have difference between the models. In fact, generating one from the other, or boiler plate code for all of them from a common meta source makes sense.

  • bigger systems may be structured in a way where a common database in the background offers a larger data model shared by different applications or "bounded contexts", each accessing a different part of the system, maybe from a different point of view, but not completely disjoint. Normalization rules and the goal of storing each piece of information in one and only one place then can lead to differences between the data model and a domain model.

Note this is still a simplification, there are many more scenarios possible, like bigger systems using a microservice architecture, where each service is small and has its own persistence model, or bigger systems with a huge, shared domain model layer, where the domain model and data model are guaranteed to correspond to each other by generators. Other scenarios may have (1) a domain model, (2) a data model in client code and (3) a database model, and all three differ to some degree.

So after this length introduction, what am I trying to tell? Well, my point is: if the data model and the domain model should be identical is nothing which is dictated by the mapping strategy.

It is quite the other way round: the overall architecture of the system tells you how the models are structured, and then you pick a suitable mapping strategy. Of course, where you are free to make choices in design, you should avoid to introduce unnecessary differences between the models as long as there is no real reason for doing so.

For example, names and types for corresponding attributes should be identical or follow strict mapping rules. That can lead to a situation where mapping all attributes of a class leads to simpler code than mapping only the subset of the attributes your program needs today. For this case, I would recommend to start with all attributes and optimize in case you notice this to be a real, measurable bottleneck.