Search code examples
entitydomain-driven-designaggregaterootdesign-principles

How to reference AggregateRoot internal entity data in DDD


I'm interested in the Idea of DDD but I have some questions about the concept of encapsulating and protecting the AggregateRoot internal Entities and how to reference them. I created a simple example (don't hit me if the domain design is bad, this is just an example to clarify the question).

// can be referenced from outside, is aggregate root
public class Library : AggregateRoot
{
   IList<Shelf> shelfs { get; }
}

// can be referenced from outside, is aggregate root
public class Shelf : AggregateRoot
{
   Book GetBookById(Guid Id) {...}
}

// should be accessed through Shelf, not referenced outside the context
public class Book : Entity<Guid>
{
   Guid Id { get; } // or something else uniqe, e.g. ISBN
}

// how to reference a book here?
// I think, I should not use Id because this is internal and
//only valid for Shelf Aggregate (but I can't have a second one of this book)
public class Lending : AggregateRoot
{
   // feels wrong because of passing internals from Shelf
   Guid LendedBook { get; set; }

   // should I Clone() an object with unique identity, is this allowed in DDD?
   Book LendedBook { get; set;}

   // create separate type for lending (but what should this type cointain)
   LendedBookInfo LendedBook { get; set;}
}

Hope to get a clear answer, cause most samples are only about ValueObjects (that are easy, 'cause they are copied anyway and not really referenced). I used C# style of code for my sample, but any other programming language or pseudo code is also welcome as answer.


Solution

  • Your example of an external ID usage

    Guid LendedBook { get; set; }
    

    is fine. What you could do to make the model more explicit, is to create a value object BookId and use that one to reference books. The value object BookId is then a context-wide concept, i.e. not one that is local to a specific aggregate.

    Apart from that, you probably don't want public setters or IList as return type in your model. But I suppose that's just an example and not really the question here.