как хранить в БД граф value object

Задача: имеется доменная модель состоящая из классов

public class EntityA {
    private UUID id;
    private String someValue;
    private Set<ValueObjectA> valueObjects;
    //... остальной код
}

public class ValueObjectA {
    private final String someValue;
    private final Set<ValueObjectB> valueObjects;
    //... остальной код
}

public class ValueObjectB {
    private final String someValue;
    //... остальной код
}

Как видно из названия классов - объекты типа EntityA являются сущностями(в терминах DDD), а объекты типов ValueObjectA и ValueObjectB - объектами значениями. Нужно определить каким образом хранить в БД данный граф объектов.

Что вызвало у меня трудности: связь между EntityA и ValueObjectA - один-ко-многим, между ValueObjectA и ValueObjectB тоже один-ко-многим. В этом случае логично для каждого класса создать отдельную таблицу в БД и связать эти таблицы между собой. Проблема возникает в связывании этих таблиц. Я не хочу добавлять в классы ValueObjectA и ValueObjectB идентификаторы, хочу чтобы они остались полноценными value object. В этом случае связать таблицы EntityA и ValueObjectA очень просто, а вот как связать таблицы ValueObjectA и ValueObjectB - я ума не приложу.


Ответы (1 шт):

Автор решения: Roman Konoval

Сначала замечу, что для value object неприменимо понятие мощность cвязи. Мощность связи определена для связи между сущностями. По-этому, некорректно говорить

связь между EntityA и ValueObjectA - один-ко-многим

Вы пишете

не хочу добавлять в классы ValueObjectA и ValueObjectB идентификаторы, хочу чтобы они остались полноценными value object.

Так вам этого и не нужно делать. Для хранения EntityA.valueObjects вам нужна таблица ENTITY_A_VALUE_OBJECT_A, в которой нужен только внешний ключ на ENTITY_A.ID. Репозиторий при загрузке EntityA прочитает ассоциированные записи из ENTITY_A_VALUE_OBJECT_A. Аналогично для ValueObjectB создайте таблицу ENTITY_A_VALUE_OBJECT_A_VALUE_OBJECT_B и там точно так же храните внешний ключ на ENTITY_A. Своего идентификатора ни у ValueObjectA ни у ValueObjectB нет и поле в классе не нужно.

Альтернативный вариант это сериализировать Set<ValueObjectA> одно значение (может быть строка json/xml/свой формат, или просто массив байт) и хранить в поле в таблице ENTITY_A.

→ Ссылка