3

I looked through a lot of articles, blogs, and SO topics about separating domain object and data models. Almost every answer said: You should have separate classes for the domain and data persistence, because...

I understand why it is good, but I haven't found any even pseudo example to solve this problem, and I have following thoughts - maybe everyone knows that it should be implemented in this way, but no one does it?

In my solutions, I'm using Automapper to achieve this (mapping domain to DB model, and domain to DTO's), but I would like to compare my approach with any other, but as I mentioned I can't find any good example.

Maybe there are just words about good practices which do not exist in real, working applications, and it is easier to use just domain classes as data models used by form, which can give a lot of benefits like caching or change tracking?

I'm currently working on an application, where data are stored in the old database, which scheme... sucks a lot, so using DB models as domain models, in this case, causes that my domain sucks too.

What do you think about this?

ORM features && faster development process > separating domain and data models && slower development process?

2

Don't write another copy of your data model in C# code when you already have that data model in the database. What would be the point?

Focus your attention on the real problem, which is mapping from that datamodel in the DB to the domain model.

ORMs do that.

So the only reason not to use an ORM would be that you have an even better way of doing the mapping.

Which is not impossible: the Dapper "micro-ORM" is very popular—it's good enough to power StackOverflow and is excellent for a lot of use cases.

If you do go the micro-ORM (or ADO, or raw SQL) route, you may well end up creating DTO classes to hold the data you get out of the db. That doesn't mean you are trying to build a model though. (And yes, for mapping to and from DTOs, AutoMapper has appeared in most places I've worked the past few years. I find that errors in automapper code are really painful to track down, but maybe that's because it is easy to use and abuse).

Yes to a separate data model, but you already have one. So Yes to an ORM if that's the cheapest/most effective way to do mapping.

I found this article–and some of the comments–quite perceptive: enterprisecraftsmanship having-the-domain-model-separate-from-the-persistence-model

0

I've came up with a NuGet package, which helps me doing exactly what you said. I'm using the classical DDD approach:

  • Domain --> DataModel = AutoMapper
  • Domain --> DTO = AutoMapper
  • DataModel --> Domain = Factory
  • DTO --> Domain = Factory

On first glance, it seems like hell of a overkill to have 3 models, but it allows us to design the domain without having ever to bother with technical concerns, for example having to set read only fields as private setters, because the ORM can't set read only fields etc.

The whole Repository layer code can be found here: https://github.com/DrMueller/MLH.DataAccess Currently, it's using a MongoDB, but the pattern is pretty much the same. An example how to use it, can be found here: https://github.com/DrMueller/MLH.WebApiExtensions

How it works:

Domain Model:

public class Individual : AggregateRoot
{
    public Individual(string id, string firstName, string lastName, DateTime birthdate)
        : base(id)
    {
        Guard.ObjectNotNull(() => firstName);
        Guard.ObjectNotNull(() => lastName);

        FirstName = firstName;
        LastName = lastName;
        Birthdate = birthdate;
    }

    public DateTime Birthdate { get; }
    public string FirstName { get; }
    public string LastName { get; }
}

create a Repository for the Aggregate Root, for example:

public class IndividualRepository : RepositoryBase<Individual, IndividualDataModel>
{
    public IndividualRepository(IDataModelRepository<IndividualDataModel> dataModelRepository, IDataModelAdapter<IndividualDataModel, Individual> dataModelAdapter) : base(dataModelRepository, dataModelAdapter)
    {
    }
}

A datamodel, which represents the "Entity":

public class IndividualDataModel : DataModelBase
{
    public DateTime Birthdate { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

And a DataModelAdapter, which maps in both directions:

public class IndividualDataModelAdapter : DataModelAdapterBase<IndividualDataModel, Individual>
{
    private readonly IIndividualFactory _individualFactory;

    public IndividualDataModelAdapter(IIndividualFactory individualFactory, IMapper mapper) : base(mapper)
    {
        _individualFactory = individualFactory;
    }

    public override Individual Adapt(IndividualDataModel dataModel)
    {
        return _individualFactory.Create(
            dataModel.FirstName,
            dataModel.LastName,
            dataModel.Birthdate,
            dataModel.Id);
    }
}

That's pretty much it, the implementation of the Repository has access to the datamodel and queryables, and the Interface works just with the Domain Models.

To answer your question: The infrastructure code can be easily made so generic, that there are minimal delays. All you need to do is to keep the possibility to define the mapping and overrule it for special needs.

  • I don't see a "Domain Model" anywhere in this. The root of the question is about separating the Domain Model (business logic) from the Data Model (persistence logic). – Greg Burghardt Sep 25 '18 at 13:00
  • I've added an exemplary Aggregate Root, but it doesn't matter that much, what concretely the domain model is. The big factor is the mapping between the central domain model and it's "infrastructure model. – Matthias Müller Sep 25 '18 at 13:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.