user1877150
user1877150

Reputation: 31

Managing persistence in DDD

Let's say that I want to create a blog application with these two simple persistence classes used with EF Code First or NHibernate and returned from repository layer:

public class PostPersistence
{
   public int Id { get; set; }
   public string Text { get; set; }
   public IList<LikePersistence> Likes { get; set; }
}

public class LikePersistence
{
    public int Id { get; set; }
    //... some other properties
}

I can't figure out a clean way to map my persistence models to domain models. I'd like my Post domain model interface to look something like this:

public interface IPost
{
   int Id { get; }
   string Text { get; set; }
   public IEnumerable<ILike> Likes { get; }
   void Like();
}

Now how would an implementation underneath look like? Maybe something like this:

public class Post : IPost
{
   private readonly PostPersistence _postPersistence;
   private readonly INotificationService _notificationService;

   public int Id 
   { 
       get { return _postPersistence.Id }
   }

   public string Text 
   { 
       get { return _postPersistence.Text; }
       set { _postPersistence.Text = value; }
   }

   public IEnumerable<ILike> Likes
   {
       //this seems really out of place
       return _postPersistence.Likes.Select(likePersistence => new Like(likePersistence ));
   }

   public Post(PostPersistence postPersistence, INotificationService notificationService)
   {
       _postPersistence = postPersistence;
       _notificationService = notificationService;
   }

   public void Like()
   {
       _postPersistence.Likes.Add(new LikePersistence());
       _notificationService.NotifyPostLiked(Id);
   }
}

I've spent some time reading about DDD but most examples were theoretical or used same ORM classes in domain layer. My solution seems to be really ugly, because in fact domain models are just wrappers around ORM classes and it doens't seem to be a domain-centric approach. Also the way IEnumerable<ILike> Likes is implemented bothers me because it won't benefit from LINQ to SQL. What are other (concrete!) options to create domain objects with a more transparent persistence implementation?

Upvotes: 3

Views: 1964

Answers (2)

eulerfx
eulerfx

Reputation: 37739

One of the goals of persistence in DDD is persistence ignorance which is what you seem to be striving for to some extent. One of the issues that I see with your code samples is that you have your entities implementing interfaces and referencing repositories and services. In DDD, entities should not implement interfaces which are just abstractions of itself and have instance dependencies on repositories or services. If a specific behavior on an entity requires a service, pass that service directly into the corresponding method. Otherwise, all interactions with services and repositories should be done outside of the entity; typically in an application service. The application service orchestrates between repositories and services in order to invoke behaviors on domain entities. As a result, entities don't need to references services or repositories directly - all they have is some state and behavior which modifies that state and maintains its integrity. The job of the ORM then is to map this state to table(s) in a relational database. ORMs such as NHibernate allow you to attain a relatively large degree of persistence ignorance.

UPDATES

Still I don't want to expose method with an INotificationService as a parameter, because this service should be internal, layer above don't need to know about it.

In your current implementation of the Post class the INotificationService has the same or greater visibility as the class. If the INotificationService is implemented in an infrastructure layer, it already has to have sufficient visibility. Take a look at hexagonal architecture for an overview of layering in modern architectures.

As a side note, functionality associated with notifications can often be placed into handlers for domain events. This is a powerful technique for attaining a great degree of decoupling.

And with separate DTO and domain classes how would you solve persistence synchronization problem when domain object doesn't know about its underlying DTO? How to track changes?

A DTO and corresponding domain classes exist for very different reasons. The purpose of the DTO is to carry data across system boundaries. DTOs are not in a one-one correspondence with domain objects - they can represent part of the domain object or a change to the domain object. One way to track changes would be to have a DTO be explicit about the changes it contains. For example, suppose you have a UI screen that allows editing of a Post. That screen can capture all the changes made and send those changes in a command (DTO) to a service. The service would load up the appropriate Post entity and apply the changes specified by the command.

Upvotes: 2

user1568656
user1568656

Reputation: 59

I think you need to do a bit more research, see all the options and decide if it is really worth the hassle to go for a full DDD implementation, i ve been there myself the last few days so i ll tell you my experience.

EF Code first is quite promising but there are quite a few issues with it, i have an entry here for this Entity Framework and Domain Driven Design. With EF your domain models can be persisted by EF without you having to create a separate "persistence" class. You can use POCO (plain old objects) and get a simple application up and running but as i said to me it s not fully mature yet.

If you use LINQ to SQL then the most common approach would be to manually map a "data transfer object" to a business object. Doing it manually can be tough for a big application so check for a tool like Automapper. Alternatively you can simply wrap the DTO in a business object like

  public class Post
   {
      PostPersistence Post { get; set;}
      public IList<LikePersistence> Likes { get; set; }
       .....
   }

NHibernate: Not sure, havent used it for a long time.

My feeling for this (and this is just an opinion, i may be wrong) is that you ll always have to make compromises and you ll not find a perfect solution out there. If you give EF a couple more years it may get there. I think an approach that maps DTOs to DDD objects is probably the most flexible so looking for an automapping tool may be worth your time. If you want to keep it simple, my favourite would be some simple wrappers around DTOs when required.

Upvotes: 0

Related Questions