Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
670 views
in Technique[技术] by (71.8m points)

domain driven design - DDD: should local Entity identity include the parent's?

In DDD, Entities have this concept of identity that uniquely identifies every instance regardless of all the other properties. Usually this identity has to be unique among the BC in which the Entity live, but there is an exception.

Sometimes we need to create Aggregates that are not only made by the root Entity and some Value Objects but have one or more child / nested Entities (that I understand to be called local Entities). For this kind of Entities the identity has only to be locally unique i.e. unique among the Aggregate boundaries.

Given this, let's also consider the fact that are two way to model a has-a relationship in DDD, depending on the actual business needs: separate Aggregates or Aggregate Root + child Entities.

In the first case the "child" Aggregate of the relation has a reference to the identity of the parent one, which in turn usually has a factory method to create and return an instance of the child:

class ForumId extends ValueObject
{
  // let's say we have a random UUID here
  //  forum name is not a suitable identifier because it can be changed
}

// "parent" aggregate
class Forum extends AggregateRoot
{
  private ForumId _forumId;
  private string _name;

  method startNewThread(ThreadId threadId, string title): Thread
  {
    // make some checks, maybe the title is not appropriate for this forum
    //  and needs to be rejected

    ...

    // passing this forum's ID,
    return new Thread(this->_forumId, threadId, title)
  }
}

class ThreadId extends ValueObject
{
  // let's say we have a random UUID here
  //  thread title is not a suitable identifier because it can be changed
}

// "child" aggregate
class Thread extends AggregateRoot
{
  private ForumId _forumId;
  private ThreadID _threadId;
  private string _title;
}

If we consider instead the second case, let's say because for some business reason we need to have Thread as a local entity of Forum, what is the correct way to identify it? Should Thread still contain the ForumId of the parent Forum or it is redundant since it will only live inside that specific Forum and never accessed outside?

Which way is better and more importantly why? May the data model (i.e. the database level) steer the decision toward one way or another, or should we still ignore it as per good DDD design?

class Forum extends AggregateRoot
{
  private ForumId _forumId;
  private string _name;
  private List<Thread> _threads;

  method startNewThread(string title): ThreadId
  {
    // or use and injected `ThreadIdentityService`'s `nextThreadId(ForumId)` method
    var threadId = this.generateNextLocalThreadId()
    var newThread = new Thread(/*this->_forumId, */ threadId, title)
    this._threads.append(newThread)
    return threadId
  }
}

// "child" aggregate - case 1
class Thread extends LocalEntity
{
  private ForumId _forumId;
  private ThreadID _threadId;
  private string _title;
}

// "child" aggregate - case 2
class Thread extends LocalEntity
{
  private ThreadID _threadId;
  private string _title;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

So the main purpose of having an aggregate is to make any change to this aggregate atomic. The aggregate root contains the full child entity inside, for example Forum would have a collection of Threads. Since the Thread is already inside a Forum wouldn’t make any sense having ForumId inside since the repository in charge of saving it would already know that id because we’d save the whole forum not a single thread.

Also wanted to add that Forum aggregate seems to be a huge aggregate, that implies some trade offs that you should take into account.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...