Doctrine: bounded context a schema tool

fordo.pytlik
Člen | 26
+
0
-

Ahoj,

potřeboval bych trochu nakopnout, zda má úvaha je správná. Budu moc rád, za každé nakopnutí!

Aktuální stav

Máme větší aplikaci v Nette+Kdyby\Doctrine se spoustou entit. Několik entit už je obludně velké (stovky metod) a rád bych je rozdělil. Nejsem moc dobrý v teorii, ale mj. jsem viděl video https://www.youtube.com/watch?… od @mkoubik.

Změna

Takže pokud vyčlením z aplikace jeden kontext (např. vytvoření objendávky – budu mu říkat App\Model\CreateOrderContext), tak mi pravděpodobně vzniknou dvě (a více) entit nad stejnou tabulkou. Například u objendávky App\Model\CreateOrderContext\Order a někde zbyde „stará“ Order (např. App\Model\Orm\Order). Podobně by to bylo i u dělších entit.

Takto mi to dává smysl – asi těžko přemigruju celou db za jedno dopoledne, pak mi vytvořím další kontexty, takže postupně budu odmazávat ze steré objednávky až ji smažu…

Problém

V aplikaci mi vzniknou dvě entity nad stejnou tabulkou. A pokud chci použít schemaTool (z CLI orm:schema-tool:update --dump-sql, tak mi to vrází chybu:

In SchemaException.php line 109:

  The table with name 'db.order' already exists.

Je něco na co jsem zapomněl? je má úvaha v pořádku, že je super mít v kódu několik objektů Objednávky podle daného kontextu? mohu SchemaTool nějak „opravit“, aby všechny objekty nejdřív mergnul, nebo se mám smířit s tím, že ho prostě nemám používat?

Doufám, že jsem to popsal nějak srozumitelně. Celý příspěvek, jsem několikrát přepisoval, aby to dávalo smysl – tak snad se to povedlo.

Jan Endel
Člen | 1016
+
+1
-

Ahoj,

ano, jde toho docílit naštěstí, a to Single table inheritance

vytvoříš si nějakou entitu „BaseOrder“ ve které budeš mít identifikátor entity a tu podědíš do dvou různých entit pro různé kontexty.

MajklNajt
Člen | 471
+
+1
-

Ahoj, ja to chápem tak, že cieľom je vytvoriť 2 samostatné entity Order, kde každá bude mať svoje vlastnosti potrebné pre daný bounded context, v prednáške spomínal, že by sa nemali dediť, čiže STI by som vylúčil – skôr by som to riešil OneToOne reláciou…

Editoval MajklNajt (2. 7. 2018 13:37)

fordo.pytlik
Člen | 26
+
0
-

Děkuji za odpovědi. Potřeboval jsem chvilku času, aby se v tom pohrabal.

@MajklNajt: s tou dědičností je dobrá poznámka.

přiznám se, že vůbec nerozumí, jak v tomto případě použít OneToOne relaci – tu přece používáme, abychom do jedné entity vložily data ze dvou tabulek. Ale já chci mí data nadále uložena v jedné tabulce. Můžeš tu myšlenku trochu rozvinout?

@JanEndel : zkoušel jsem to a bohužel to nefunguje – pravděpodobně jsem něco nepochopil. Když se vrátím zpátky do stavu „Aktuální stav“ popisovaný v mém prvním příspěvku, tak udělám:

  1. vytvořím abstraktní BaseOrder (přidal ji anotaci @InheritanceType("SINGLE_TABLE") a samozřejmě @Entity), doplním protected $id s odpovídající anotací
  2. původní objednávku přejmenuji na DefaultOrder (já vím, debilní název, ale zatím nevadí), odeberu $id a nastavím, že dědí od BaseOrder
  3. vytvořím novou objdnávku např FooOrder (zase doplním anotace @Entity, zase dědí od BaseOrder)

Nic víc, nic míň a když teďka chci vytáhnout jednu FooOrder (např. dle ID), tak mi to píše, že nemáže najít sloupec dtype. (Protože je to výchozí sloupec na základě chce Doctrine rozhodnout, zda použije FooOrder nebo DefaultOrder: viz https://www.doctrine-project.org/…ference.html#…)

Opravdu je Single table inheritance ta správná cesta? já přece nechci aby doctrine rozhodovala o tom, jakou entitu má vytáhnout, já ji to explicitně říkám v tý query:

/**
 * @param int $id
 * @return Query
 */
protected function createQuery(int $id)
{
    return $this->entityManager->createQueryBuilder()
        ->select('u')
        ->from(App\Model\Orm\FooOrder, 'u') // nebo klidně App\Model\Orm\CreateOrderContext\Order - to je jedno
        ->andWhere('u.id = :id')->setParameter('id', $id)
        ->getQuery();
}
fordo.pytlik
Člen | 26
+
0
-

Přiznám se, že mi to nedá spát :-), tak se snažím načíst alespoň nějakou teorii – narazil jsem na issue:

https://github.com/…/issues/4091 – se píše, že to prakticky není možné, protože:

  1. řešení, které jsem popisoval v prvním příspěvku nefunguje právě SchemaTool
  2. řešení pomocí STI by způsobilo, že by v paměti mohly být dvě entity reprezentující stejný objekt (kdyby se změnila jedna, tak

Rozumím tomu správně? Když jsem koukal na danou přednášku, měl jsem pocit, že to je prostě „normální“ řešení a nyní to vypadá jako něco strašně složitého.

Felix
Nette Core | 1189
+
+1
-

Nikdy jsem to realne takto striktne neimplementoval. Ale take nevim, jak bych to s Doctrine resil. U ActiveRecord nebo DoctrineDBAL by to slo snadneji, ale tam to zase neni uplne DDD.

Trochu se mi zda, ze by mohlo pomoci CQRS, kde celkem jasne oddelen zapis a cteni. Takze se ti nemuze stat, ze by jsi me v pameti, jak rikas, 2 entity.

Pripadne mit vice mikrosluzeb, kde kazda cast by si to vyresila podle sebe. Tak ci onak, na tohle je potreba imho myslet na zacatku a dobre to rozmyslet. Neni lehke to pak menit.

Ale treba by mel nekdo jiny nazor. :)

fordo.pytlik
Člen | 26
+
0
-

Ahoj, @Felix – díky za odpověď.

Abych řekl pravdu, tak to, že v paměti budou dvě entity stejného typu mě aktuálně vůbec netrápí. Myslím, že v mém případě by se to vůbec stát nemělo, protože když řeším jeden BC, tak nebudu načítat entitu z jiného kontextu, ale třeba se pletu.

Ve zkratce: hrozně se mi líbí myšlenka, že bych rozsekal obrovskou entitu Order na cca 3 kontexty. To je hlavní cíl.

Ale překvapilo mě, že pak nemůžu použít SchemaTool – zatím se zdá, že je to jediný problém toho řešení z prvního příspěvku (třeba jsem ještě nějaký přehlédl) – taky bych mohl žít bez něj, ale to by byla asi škoda…

MajklNajt
Člen | 471
+
0
-

Ahoj @fordo.pytlik, ja si práveže myslím, že cieľom toho všetkého je rozsekať jednu entitu na 3 samostatné entity, ktoré budú iba prepojené (preto som písal o OneToOne relácií). Prednášku o DDD som pochopil tak, že vo všetkých kontextoch použijem entitu s rovnakým názvom Order (rozdiel bude napr. iba v namespace), avšak v každom kontexte využívam (tým pádom aj mapujem) iné properties, pretože v kontexte expedície nikoho nezajíma fakturačná adresa, dátum objednávky ani pod akým symbolom očakávam úhradu, zaujímajú ma napr. len položky a adresa dodania; v kontexte párovania platby s objednávkou ma zas zaujíma práve ten variabilný symbol, ale je mi jedno, či je to objednávky ponožiek alebo jadrovej ponorky, riešim len zaevidovanie platby…

Ty to zrejme chceš napchať do jednej tabuľky, ja by som to naopak rozdelil kľudne do viacerých tabuliek, koniec koncov, pri modelovaní objektov by ťa štruktúra SQL ani nejako nemala trápiť :)

fordo.pytlik
Člen | 26
+
0
-

Díky za odpověď. Nevím, jestli jsem to pochopil úplně správně (ať už tvůj příspěvek, nebo již zmíněnou přednášku).

Pochopil jsem to tak, že by právě jednotlivé entity (z jiných BC měly být naprosto odděleny (tj. bez propojení relací OtO).Tak by mi to dávalo větší smysl (ale třeba se pletu).