Страница 1 из 1
Аггрегат и коллекция
Добавлено: 2017.12.22, 21:14
noLogicOnlyWar
Есть аггрегат пусть будет класс X, он содержит коллекцию сущностей Y. Требуется реализовать перенос сущности Y из одного экземпляра X в другой X. При этом перед переносом нужно проверить ряд параметров, тк Y'у может быть запрещен переход в контекст нового X.
Примерный код:
Код: Выделить всё
class X {
public function moveYTo(X $x, Y $yToTransfer)
{
//добавляем к новому аггрегату
$x->addY($yToTransfer);
//удаляем из текущего
unset($this->ys[$yToTransfer]); //тут конечно не $yToTransfer а ключ
}
private function addY(Y $y)
{
//проверяем может ли y существовать в новом контексте
$this->failIfContextWrong($this, $y);
$y->changeOwnerId($this->id);
$this->ys[] = $y;
}
}
class Y {
private $ownerId;
public changeOwnerId($id)
{
$this->ownerId = $ownerId;
}
}
Смущает changeOwnerId(). Нужно сменить связь, но не хочется чтобы метод changeOwnerId был public, ибо ктонибудь другой может посмотреть на код и решить что достаточно вызвать changeOwnerId чтобы переместить Y. В cpp я так понимаю это можно решить через friend's классы. Как решаете такие ситуации? Возможно есть какой то способ обойти сию проблему?
Re: Аггрегат и коллекция
Добавлено: 2017.12.23, 00:13
samdark
1. Скорее всего не нужно в Y onwerId. Сам факт нахождения в аггрегате на это указывает.
2. Если всё-таки надо, Y можно сделать immutable:
Код: Выделить всё
class Y
{
private $ownerId;
public function __construct($ownerId, ...)
{
$this->ownerId = $ownerId;
}
}
Тогда X будет таким:
Код: Выделить всё
class X
{
private $ys = [];
public function move(Y $what, X $where)
{
$newY = new Y($where->id, $what->something, ...);
$where->add($newY);
$this->remove($what);
}
private function add(Y $y)
{
$this->ys[] = $y;
}
}
Re: Аггрегат и коллекция
Добавлено: 2017.12.23, 12:26
noLogicOnlyWar
Спасибо за ответ.
Скорее всего не нужно в Y onwerId. Сам факт нахождения в аггрегате на это указывает
Не уверен что можно обойтись без какой либо ссылки на owner, ведь зачастую нам надо будет получить аггрегат зная только id Y. Например в сервис приложения приходит реквест на update y, наши действия в этом случае будут: достать из репо y, достать из репо x через y->owner->id, вызвать x->updateY(...). И даже если разрулить такие моменты - орм все равно необходима будет ссылка на owner.
Если всё-таки надо, Y можно сделать immutable
Тоже над этим думал, но запутался в вопросах:
id нужно сохранять тк на Y->id могут быть завязаны вещи в совершенно другом месте (например где-то хранится статистика), соответственно мы должны отправить в конструктор Y id из старого Y ? Это вообще законно? id по определению уникально для сущности а мы выходит таскаем его от одной к другой... с теоретической стороны это недопустимо? или ок? К тому же иммутабельность выйдет сомнительная, ведь id у y_old и y_after_move будет одинаковый а остальные поля не факт, значит с точки зрения домена это 1 мутабельный объект?
Re: Аггрегат и коллекция
Добавлено: 2017.12.23, 16:50
zelenin
noLogicOnlyWar писал(а): ↑2017.12.23, 12:26
Спасибо за ответ.
Скорее всего не нужно в Y onwerId. Сам факт нахождения в аггрегате на это указывает
Не уверен что можно обойтись без какой либо ссылки на owner, ведь зачастую нам надо будет получить аггрегат зная только id Y. Например в сервис приложения приходит реквест на update y, наши действия в этом случае будут: достать из репо y, достать из репо x через y->owner->id, вызвать x->updateY(...). И даже если разрулить такие моменты - орм все равно необходима будет ссылка на owner.
она будет. вы же сделаете $x->add($y); дальше orm при сохранении сама все разрулит. Двойная связь ни к чему.
В вашем случае пришел id Y, по нему сразу нашли агрегат X, и дальше с ним работаете.
Re: Аггрегат и коллекция
Добавлено: 2017.12.23, 18:16
noLogicOnlyWar
zelenin писал(а): ↑2017.12.23, 16:50
она будет. вы же сделаете $x->add($y); дальше orm при сохранении сама все разрулит. Двойная связь ни к чему.
В вашем случае пришел id Y, по нему сразу нашли агрегат X, и дальше с ним работаете.
Спасибо, тогда немного конкретики, как это сделать в доктрине? судя по докам только как One-To-Many, Unidirectional with Join Table ? что для меня не очень хорошая новость, тк хотелось бы замапить на уже существующую структуру бд, в которой у таблицы Y просто есть поле owner_id
Re: Аггрегат и коллекция
Добавлено: 2017.12.23, 18:30
zelenin
noLogicOnlyWar писал(а): ↑2017.12.23, 18:16
zelenin писал(а): ↑2017.12.23, 16:50
она будет. вы же сделаете $x->add($y); дальше orm при сохранении сама все разрулит. Двойная связь ни к чему.
В вашем случае пришел id Y, по нему сразу нашли агрегат X, и дальше с ним работаете.
Спасибо, тогда немного конкретики, как это сделать в доктрине? судя по докам только как One-To-Many, Unidirectional with Join Table ? что для меня не очень хорошая новость, тк хотелось бы замапить на уже существующую структуру бд, в которой у таблицы Y просто есть поле owner_id
а какая структура сейчас?
Re: Аггрегат и коллекция
Добавлено: 2017.12.23, 18:50
noLogicOnlyWar
Таблица X, таблица Y с полем x_id для связи
Re: Аггрегат и коллекция
Добавлено: 2017.12.23, 19:13
zelenin
noLogicOnlyWar писал(а): ↑2017.12.23, 18:50
Таблица X, таблица Y с полем x_id для связи
http://docs.doctrine-project.org/projec ... irectional
то, что это bidirectional, не значит что надо обязательно поддерживать двухстороннюю связь, предоставляя Y публичное апи для добавления X. Доктрина сама добавит через рефлексию. Двухсторонняя связь нужна, если вы будете работать с Y в рамках того же реквеста, но т.к. вы с Y работаете только через X (агрегат), то связь не нужна.
Re: Аггрегат и коллекция
Добавлено: 2017.12.23, 20:59
noLogicOnlyWar
Если я вас правильно понял то должен работать такой вот код :
$y = $x1->ys->get(0);
$x1->ys->remove(0);
$x2->ys->add($y);
$em->flush();
Но он не работает, выполняется как ожидаю только если добавить перед флашем $y->changeOwner($x);
Настройки мапинга дефолтные из дока, за исключением того что orphanRemoval: false
Re: Аггрегат и коллекция
Добавлено: 2017.12.23, 21:19
zelenin
да, возможно не будет работать. что впрочем тоже можно объяснить, ведь схема составлена несогласно доменному слою - получается не one X владеет many Y, а many Y владеют one X. То есть агрегат - Y, хотя должен быть X. То есть у вас в домене связь в одном направлении, а в хранилище в другом.
http://docs.doctrine-project.org/projec ... irectional
Re: Аггрегат и коллекция
Добавлено: 2017.12.23, 21:53
noLogicOnlyWar
Хм, да, так и есть, спасибо большое что прояснили.
Теоретически, в контесте разрабатываемого модуля, я думаю можно рассматривать и Y как агрегат, то есть множество Y находятся в одном контексте X. Тогда задаче по смене владельца будет решаться $y->changeOwner($newContext) и вся логика тогда уйдет в этот метод. Как думаете вывернуть вывернуть так доменную логику? Или все же способ выше это все в угоду инфраструктуры, domain first и мигрировать структуру бд?
Re: Аггрегат и коллекция
Добавлено: 2017.12.23, 22:07
zelenin
noLogicOnlyWar писал(а): ↑2017.12.23, 21:53
Хм, да, так и есть, спасибо большое что прояснили.
Теоретически, в контесте разрабатываемого модуля, я думаю можно рассматривать и Y как агрегат, то есть множество Y находятся в одном контексте X. Тогда задаче по смене владельца будет решаться $y->changeOwner($newContext) и вся логика тогда уйдет в этот метод. Как думаете вывернуть вывернуть так доменную логику? Или все же способ выше это все в угоду инфраструктуры, domain first и мигрировать структуру бд?
такое нормально, что член одного агрегата может быть корнем другого агрегата. но в данном случае кажется, что вы именно в угоду зранилищу меняете.