ormdomain-driven-designpocodata-access-layer

Data access layer design in DDD


Excuse me for my poor English.

Ok, I'm thinking about DDD approach now and it sounds great but... There is one little question about it. DDD says that the domain model layer is totally decoupled from the data access layer (and all other layers). So when the DAL will save some business object it will have access to public properties of this object only. Now the question:

How can we guarantee (in general) that a set of public data of an object is all we need to restore the object later?

Example

We have the following business rules:

  1. User and domain must be provided for the business object on create.
  2. User and domain cannot be changed after object creation.
  3. The business object have the Email property which looks like "user@domain".

Here is a pure POCO which describes those rules:

public class BusinessObject
{
    private string _user;
    private string _domain;

    public BusinessObject(string user, string domain)
    {
        _user = user;
        _domain = domain;
    }

    public string Email
    {
        get { return _user + "@" + _domain; }
    }
}

So at some moment the DAL will save this object to the external storage (i.e. SQL database). Obviously, the DAL will save the "Email" property to the associated field in DB. Everything will work just fine until the moment when we'll ask the DAL to restore the object. How the DAL can do this? The object must have a public setter for the "Email" field at least. Something like

public string Email
{
    set
    {
        string[] s = value.Split("@");
        _user = s[0];
        _domain = s[1];
    }
}

Actually, the object will have public getters/setters for both "User" and "Domain" fields and method GetEmail(). But stop. I don't want my POCO to have such functionality! There are no business rules for it. This must be done for the ability to save/restore the object only.

I see another option. The ORM which is a part of the DAL could be asked to store all of the private fields needed to restore the object. But this is impossible if we want to keep the domain model separated from the DAL. The DAL cannot rely on certain private members of the business object.

The only workaround I can see is to have some system-level instrument which can create the dump of the object for us and can restore object from this dump anytime. And the DAL must put this dump to the storage in addition to public properties of the object. So when the DAL needs to restore the object from storage it will use the dump for this. And the public properties saved to storage can be used when the DAL is performing operations that don't need the object to be instantiated (i.e. most of link2sql queries).

Am I doing it wrong? Do I need read more? About some patterns, ORM's maybe?


Solution

  • I think you got this part wrong:

    I see another option. The ORM which is a part of the DAL could be asked to store all of the private fields needed to restore the object. But this is impossible if we want to keep the domain model separated from the DAL. The DAL cannot rely on certain private members of the business object.

    Domain model does not depend on DAL. Its the other way around, DAL depends on Domain model. ORM has intimate knowledge of Domain Objects, including private fields. There is absolutely nothing wrong with that. In fact this is the best way to implement persistent-ignorance in DDD. This is how the Domain class can look like. Note that

    The only thing DAL/ORM needs is private parameterless consturctor:

    public class BusinessObject {
        private readonly string _user;
        private readonly string _domain;
        
        private BusinessObject(){}
     
        public BusinessObject(string user, string domain) {
            _user = user;
            _domain = domain;
        }
    
        public string Email {
            get { return _user + "@" + _domain; }
        }
    }
    

    And the magic happens in ORM. Hibernate can restore this object from database using this mapping file:

    <class name="BusinessObject" table="BusinessObjects">
        ...
        <property name="_user" column="User" />
        <property name="_domain" column="Domain" />
        ...
    </class>
    

    Another aspect of persistence-ignorant domain code is DDD Repository:

    Definition: A Repository is a mechanism for encapsulating storage, retrieval, and search behavior which emulates a collection of objects.

    Repository interface belongs to Domain and should be based on Ubiquitous Language as much as possible. Repository implementation on the other hand belongs to DAL (Dependency Inversion Principle).