5
public class AggregateRoot {
     private Integer id;

     private Set<Child> children;
}

public class Child {
     private Integer id;
     private String name;
}

Imagine that you need to save Child and to send his ID to the some external system. In DDD you will save child with code similar to this:

AggregateRoot aggregateRoot = aggregateRootRepository.getById(id);
Child child = new Child();
child.setName("Sun");
aggregateRoot.addChild(child);
aggregateRootRepository.save(aggregateRoot);
externalService.postSavedChildId(child.getId());

Of course child.getId() will return null because it is not in persistence context. Any idea how this case should be handled in DDD?

theDmi
  • 17,546
  • 6
  • 71
  • 138
mommcilo
  • 956
  • 11
  • 28

2 Answers2

5

There are two problems in your case, which I will address separately:

  • How should we hand out IDs of non-aggregate-root entities?
  • How do we obtain an ID of an entity before saving, when using DB-generated IDs?

References to Non-Aggregate-Root Entities

DDD suggests that aggregate roots carry global IDs, while "inner" entity IDs have only local significance. So you should not expose the inner ID alone, as it will not uniquely address the entity.

  1. Split the two entities and make the inner entity an aggregate of itself. Now it has global identity and becomes addressable from the outside world.
  2. If (1) does not make sense in your domain, expose a combined ID to the external system. You must be able to separate the combined ID into the aggregate root ID and the (local) inner entity ID.

DB-Generated IDs

Using DB-generated IDs does not fit well with DDD for the reasons you experienced. The best approach is usually to use generated random IDs. This answer has more information about the topic.

Side Note

From reading your question, I get the impression that you take a rather DB-centric approach (using DB-generated IDs is one indication of that). When using DDD, try to focus on the domain model first and build the DB infrastructure around it.

Community
  • 1
  • 1
theDmi
  • 17,546
  • 6
  • 71
  • 138
  • I came with same conclusion, so I will accept this like an answer. Because I was concentrated on DB id, but after a while I realized it should be an GUID eg. – mommcilo Jan 16 '16 at 11:08
3

Imagine that you need to save Child and to send his ID to the some external system

You cannot do it. Entities within an aggregate have local identities, which means it is impossible to access these entities from the outside the aggregate. The only entity accessible from the outside of an aggregate, meaning having a global identity, is the aggregate root.

So it seems the entity, whose ids you want to provide to an external system, is actually an aggregate root.

Another question is, why do you expose the database ids of entities of one system to another system? Systems should not depend on the database ids of other systems. They should use business ids instead.

Adam Siemion
  • 15,569
  • 7
  • 58
  • 92
  • I don't want actually to access them directly. But imagine that child entity should be edited for example, based on some action from external system. I will do it throw AR but I need to know some identifier of child entity. And you are right, in this case business ids are more acceptable then DB ids. – mommcilo Jan 16 '16 at 11:13