Optimum Ways To Restore A Domain Object From Persistence

By Mike on 6 April 2012

Update Strategies To Restore Domain Entities

Let's say we have this object (the actual definition is not important)

public class QueueItem
    {    
        public QueueItem(int blogId,string name,Type command,object data)
        {
            if (name == null) throw new ArgumentNullException("name");
            if (command == null) throw new ArgumentNullException("command");
            BlogId = blogId;
            CommandType = command;
            ParamValue = data;
            CommandName = name;
            AddedOn = DateTime.UtcNow;
        }

      
        public Guid Id { get; internal set; }
        public int BlogId { get; private set; }
        public string CommandName { get; set; }
        public Type CommandType { get; private set; }
        public object ParamValue { get; private set; }
        public DateTime AddedOn { get; private set; }
        public DateTime? ExecutedOn { get; private set; }
        public void ExecuteIn(ILifetimeScope ioc)
        {
            throw new NotImplementedException();
        }
    }

This domain object will be handled by a repository

public interface IRepository
{
     void Save(QueueItem item);
     QueueItem Get(Guid id);
}

The repository persists the object, but also has to restore it. And here lies our problem. When implementing the repository, how can we restore the domain object, respecting the encapsulation and without  requiring the object to provide special behaviour for this task.

It turns out that it depends.

Now, when designing the domain object, the design should not care about the persistence needs, it isn't the object's responsibility to know about storage, serializing and deserializing, that's the repository's concern. In this example, when a QueueItem is created, some values are supplied, but the AddedOn property is automatically set by the object. When restoring the object, the repository obviously can't use that constructor, so it needs a way to fill in all the values.

There are several ways, which are most obvious but all have the same flaw: they require that the object change just for this purpose and that's not good.

  1. Having another constructor that has all the values as arguments.
    This solution may work,  but:
    • That constructor is available everywhere and you'd have to specify in comments that that constructor is to be used only for restoring the object. Pretty ugly.
    • If the object has many fields then the constructor needs to accept LOTS of arguments, which is not a pretty sight.
  2. Making all the fields/properties setters public.
    This is probably the worst solution, as it breaks the encapsulation. Don't do it! Ever!
  3. Provide a factory method.
    This is actually the best solution from this group. The domain will keep its encapsulation and the static method won't interfere with the actual usage. Also it provides a very clear intent
    public static QueueItem Restore(Guid id,int blogId /* etc*/) {}

    However is still has the same parameters number problem as the constructor solution, but at least it depends form object to object.

 The good news is there still are other better solutions:

  1. If you're using a document database (like RavenDb) or you're storing the objects in serialized form (I recommend JSON for that) just deserialize it back or let the db do it. But most of the time you won't be using a document database nor you'll be storing the objects in JSON. However it's a good solution, if the conditions are met.
  2. Mapping. Using a mapper (I use Automapper) the domain object is created and its data its copied automatically from a provided source.

These solutions don't require to change anything in the domain object definition so the class can evolve according to the domain needs, ignoring anything persistence related (so the separation of concerns is maintained).

You might have noticed that I didn't include the case when an ORM is used. That's because an ORM is an implementation detail of the repository and the Domain Model is different from the Persistence Model handled by the ORM (I don't consider relevant the cases where those happen to be identical because of a very simplistic domain or a misuse). And being different means you still have to transfer the values from the ORM entities to the domain object.

But what if you can't use any of the good solutions above? No document db and no automapper (I find it hard to believe automapper can't be used almost anywhere but it may be the case). Then the next optimum solution is to use the factory method I've presented before. It's not the best but it's a good compromise. Of course, if the object is very complex perhaps a dedicated factory is a better choice.

Comments (12) -

David
David
14 August 2013 #

I understand this article explains how to populate the domain model from a persistence model.  My question is in regards to the reverse direction, how should the repository know which persistence model(s) to update for an update operation, for example.  Since, in your example, the repository Save method accepts a domain model entity, how does it turn that into a persistence model?  Just looking for some ideas here.  I'm guessing you would use an AutoMapper maybe with an identity map pattern or something similar?

Reply

Admin
Admin
14 August 2013 #

The repository implementation knows what to save. Lately, I prefer to use mementos, which do require a bit of boring code, but simplify things a lot. Any Entity would have a GetMemento method and can be initiated with a Memento (passed as a constructor argument). Then the memento (which is a simple DTO) would be persisted in any form you want. The repository implementation just needs to get the memento and send it to db.

The repository knows about both the domain object and the persistence models, that's why it's a mediator.

Reply

David
David
14 August 2013 #

In the case of the memento pattern you mentioned, wouldn't the domain be no longer persistence ignorant?  In other words, isn't it a violation of DDD layers if the entity knows about the DTO?  What if I change db schemas and the DTO needs to morph.  How would that be handled.  Thx.

Reply

David
David
14 August 2013 #

Or is it that the memento mimics the domain model rather than the persistence model?

Reply

Admin
Admin
15 August 2013 #

Memento is the snapshot of the object. The object itself knows what it requires in order to be restored. It's a convenience meant to keep the domain object clearly decoupled from the persistence. The point is the domain object knows only about that memento who can be considered initialization data. So the memento is actually a technical detail of the entity. It's the Memento pattern with the twist that the memento itself is a dto with public fields. Only that we're using it for persistence purpose.

Personally, I'm using CQRS so the memento would be be stored only for domain repository usage and not for querying. For querying I'd use the domain object to create a specific read (queryable) model. But you can do the querying directly on the memento if it contains the relevant information and it's stored that way. After all from the db point of view, the memento is the domain object.

Reply

David
David
15 August 2013 #

Any sample code available to demonstrate?

Reply

Eric
Eric
13 December 2013 #

Hi Mike,

You touched on the use of JSON as persistence model for the domain objects. What are the merits of this approach?

Reply

Admin
Admin
14 December 2013 #

Easy to serialize/deserialize. Of course, it's redundant if you're using a document db.

Reply

Eric
Eric
14 December 2013 #

What about bulk actions? Say you've got your CQRS implementation and the UI has served up a grid with a 'Select all' and a button that enables the user to perform some action on all the select records. In your command processing would you simply iterate through the list of ids, re-hydrate the entities and do the relevant processing on each one? What about the events generated? Would they be on a list of ids or an event or each? It is a slightly contrived scenario to some extent. In a real app you would go for what makes more sense and its probably not a 'one-size-fits-all'.

Reply

Admin
Admin
16 December 2013 #

Eric, I've answered your question in this post www.sapiensworks.com/.../...With-DDD-And-CQRS.aspx

Reply

Lars
Lars
22 March 2014 #

Another question regarding JSON.

Serializing the domain objects directly into NoSQL (MongoDB) is a simple way. But then you cannot simply change the name of a field in the DO because your already persisted DOs are serialized with the old name in the database. You lose the independence of the DOs from the persistence store.

And what about annotations that are necessary to configure the mapping from DOs to JSON (like the id, indexes)? Where to put them? Or can't you use them?

Doesn't that lead to a separate persistence model with it's own classes that are bound to the database mapper (e.g. Morphia). And the need of something like Automapper to map between DOs und POs?

Reply

Admin
Admin
25 March 2014 #

Indeed, if the DO changes often then you have to maintain the 'legacy' fields. That's why I do prefer to use the memento pattern (I intend to blog about that in the near future) for this scenario. It has its disadvantages (some code duplication) but it clearly decouples the DO from the Persistence, because the memento will be stored instead of the DO. The memento itself (a DTO) will handle legacies.

So form the db point of view, there's no DO only some data structure, the memento. The DO should know about the memento and probably you can use Automapper to map the DO to memento and back.

Reply

Add comment

biuquote
Loading