Kdyby/Doctrine – jak na M:N vazbu
- Trsak
- Člen | 22
Zdravím,
jaký je nejlepší způsob pro práci v ORM s M:N vazbou?
Jak:
- Vytvořit entity
- Vkládat data
- Vybírat data
Aktálně moje entity vypadají asi takto:
<?php
namespace App;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class Movie extends \Kdyby\Doctrine\Entities\BaseEntity
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
*/
protected $id;
/**
* @ORM\ManyToMany(targetEntity="MovieGenres")
* @ORM\JoinTable(name="movie_has_genres",
* joinColumns={@ORM\JoinColumn(name="movie_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="genre_id", referencedColumnName="id")}
* )
*/
private $genres;
}
<?php
namespace App;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class MovieGenres extends \Kdyby\Doctrine\Entities\BaseEntity
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
*/
protected $id;
/**
* @ORM\Column(type="string")
*/
protected $genre;
}
Ale není mi zcela jasné, jak s tím niní správně a efektivně pracovat.
- Svaťa Šimara
- Člen | 98
Neexistuje univerzální způsob, každý je vhodný pro jiné použití. Záleží, jak si danou situaci namodeluješ. M:N vazby jsou v reálném světě často přirozeně obousměrné, což je skvěle volné, ale opruz pro implementaci.
Jak se dívám na Tvůj příklad, tak vidím, že modeluješ:
[Movie] ---> 0..* [MovieGenres]
MovieGenres je entita nezávislá na okolí (což je super), a Movie je asociováno k 0..* MovieGenres. Pokud si rozhodneš, že do této asociace nechceš nic zaznamenávat, pak nemá smysl používat další entitu. Nechal bych to přesně, jak máš implementováno. Doctrine Ti vytvoří vazební tabulku, což je ok.
Můžeš volat: $movie->addGenres($genres)
Pokud se časem rozhodneš, že vazba bude mít něco navíc, například váhu, pak se Ti rozpadne model třeba na:
[Movie] ---> 0..* [AssociatedGenres] ---> [MovieGenres]
Ale opět, co se stalo. Mám možnost k Movie přiřadit více
AssociatedGenres (které povinně obsahuje vazbu do MovieGenres, a má vlastnost
„váha“). MovieGeneres zůstává krásně volné – po refaktoringu jej
nemusím měnit. A stejně bude existovat vazební tabulka
movie_has_associated_generes
.
Můžeš volat: $movie->addGenres($genres, $weight)
s tím,
že zvenku o entitě AssociatedGenres nebude nikdo vědět, půjde o entitu
vlastněnou čistě Movie, a pak si můžeš dovolit finty jako http://doctrine-orm.readthedocs.org/…iations.html#…
Pokud bych od začátku modeloval:
[Movie] <--- [AssociatedGenres] ---> [MovieGenres]
Pak jde o zvláštní model, Movie neví nic o MovieGeneres, což nejspíš
není cílový stav, nebo je? Pokud jo, tak se pletu. Pokud bych v Movie chtěl
pracovat s MovieGenres, nemám šanci. Něco jako
$movie->addGenres($genres)
v tomto modelu nezařídím. Leda,
že bych vazbu mezi Movie a AssociatedGenres udělal oboustrannou:
[Movie] 0..1 --- 0..* [AssociatedGenres] ---> [MovieGenres]
Do tohoto bych ale nešel, protože udržovat oboustranné asociace je dost drsné, a i Doctrine pro ně má svá omezení, která jsou logická http://doctrine-orm.readthedocs.org/…iations.html