borNfree
@borNfree
PHP developer

Как правильно сделать связь 1:M в агрегате при использовании DDD?

Подскажите, как правильно в ORM (например, в Doctrine 2) организовать связь один ко многим в Агрегате (Aggregate) между сущностями.

Возьмем пример: есть Правило (Rule) и Нарушение (Violation).
Очевидно, что Нарушения без Правила быть не может. Rule - это Aggregate Root, т.е. доступаться к Violation мы будем только через Rule.

Вопрос, как правильно тут сделать отношения?
Варианты:

  • 1:M Bidirectional, где внешний ключ `rule_id` будет в таблице `violations`.
  • 1:M Unidirectional через таблицу связку, но в таком случае будут три таблицы: `rules`, `violations`, `rule_violations`.


И, самое главное, как будет выглядеть сущность Violation - будем ли мы в конструктор передавать `$ruleId`, или Violation ничего о Rule знать не будет?

Первый вариант
class Violation
{
    public function __construct(ViolationId $vid, RuleId $rid, /* other parameters /*)
}


Второй
class Violation
{
    public function __construct(ViolationId $vid, /* other parameters /*)
}


Если это правильно хранить ruleId в сущности Violation, то как тогда сделать маппинг в ORM, ведь Doctrine работает с объектами отношениями, а не с простыми integer.

Спасибо
  • Вопрос задан
  • 646 просмотров
Пригласить эксперта
Ответы на вопрос 3
@Vicom
перепишите вопрос на русский, пожалуйста, что за
организовать связь один ко многим в Агрегате
(есть понятие Агрегации, но про Агрегаты я слышу впервые)

доступаться
(песня без слов, ночь без сна..)

..либо я серость и всё это термины из области, о которой я слишком не слышал,
т.к. изначально читаю это и думаю метамоделью UML сразу же

%публика%, растолкуй кто в лес, а кто по дрова, я только проснулся? )
Ответ написан
@GrizliK1988
По поводу настройки Doctrine применительно к DDD можно почитать здесь: https://leanpub.com/ddd-in-php. В целом весьма полезная книга.
Ответ написан
sggr
@sggr
PHP, Ruby, GO
Зачем вам interger? Зачем вам в конструктор передовать ID? Это DDD, вы работаете с объектами и их поведением, а не со свойствами объектов.
То есть
<?php
class Violation
{
    private $id;
    private $rules;
    public function __construct(ViolationID $vid, array $rules = []) {
        $this->id = $vid;
        $rules = $rules;
    }
    
    public function addRule(Rule $rule) {
        $this->rules[] = $rule;
        return $this;
    }

    public function deleteRule(Rule $rile)...
    public function getRules()...
    ...
}

class Rule
{
    private $id;
    private $violation;
    public function __construct(RuleID $rid, Violation $violation) {
        $this->id = $rid;
        $this->violation = $violation;
    }
    ...
}


Проблем с маппингом никаких быть не должно, приведу пример в yaml и рекомендую при использовании DDD и доктрины использовать external mapping.

Core\Violation:
  type: entity
  table: violation
  repositoryClass: InfrastructureBundle\Repository\PersistViolationRepository
  oneToMany:
    rules:
      cascade: [ "persist", "remove" ]
      targetEntity: Core\Rule
      mappedBy: violation
      orphanRemoval: true

Core\Rule:
  type: entity
  table: rule
  repositoryClass: InfrastructureBundle\Repository\PersistRuleRepository
  manyToOne:
    violation:
      targetEntity: Core\Violation
      inversedBy: rules
      joinColumn:
        name: violation_id
        referencedColumnName: id


UPD: Я плясал от того что одно нарушение содержит в себе несколько правил. Как я понял у вас наоборот, но сути это не меняет.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы