Associazione Symfony Mappatura OneToOne e OneToMany alla stessa entity framework;

Ho un'entity framework; View che rappresenta il record della pagina principale e quindi ho un'entity framework; associata denominata ViewVersion che memorizza più versioni dell'entity framework; mentre viene modificata nel tempo. L'entity framework; View imposta la ViewVersion "Published" ViewVersion nel field VersionId . Questo rende una semplice associazione OneToOne. Ma in alcuni contesti voglio anche get tutte le versioni associate a questa entity framework; View , ad esempio se voglio consentire all'utente di rivedere le versioni precedenti e di tornare indietro. Quindi avrò bisogno di un'altra mapping che sia OneToMany. La prima viewVersion verrà viewVersion alla versione "pubblicata" triggers e la seconda viewVersions mostrerà tutte le versioni.

Definizioni di entity framework;

 /** * @ORM\Entity * @ORM\Table(name="view") * @ORM\Entity(repositoryClass="Gutensite\CmsBundle\Entity\View\ViewRepository") */ class View extends Entity\Base { /** * @ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", inversedBy="view", cascade={"persist", "remove"}, orphanRemoval=true) * @ORM\JoinColumn(name="versionId", referencedColumnName="id") */ protected $viewVersion; /** * @ORM\Column(type="integer", nullable=true) */ protected $versionId = NULL; /** * @ORM\OneToMany(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", mappedBy="viewAll", cascade={"persist", "remove"}, orphanRemoval=true) */ protected $viewVersions; } /** * @ORM\Entity * @ORM\Table(name="view_version") * @ORM\Entity(repositoryClass="Gutensite\CmsBundle\Entity\View\ViewVersionRepository") */ class ViewVersion extends Entity\Base { /** * @ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", mappedBy="viewVersion", cascade={"persist"}) */ protected $view; /** * @ORM\ManyToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", inversedBy="viewVersions") * @ORM\JoinColumn(name="viewId", referencedColumnName="id") */ protected $viewAll; /** * The primary view entity that this version belongs to. * @ORM\Column(type="integer", nullable=true) */ protected $viewId; } 

Questo "funziona" ma si consiglia di avere due associazioni con la stessa entity framework; come questa? O questa è una pessima idea?

L'entity framework; ViewVersion farà riferimento a una singola entity framework; View in entrambi i casi, ma le associazioni mappate necessitano di due variables separate, ad esempio View e ViewAll . Non sono esattamente sicuro di come funzionano gli interni per l'associazione e come viene utilizzata la variabile di riferimento con la mapping.

In alternativa, potrei sbarazzarmi dell'associazione OneToOne e impostare semplicemente una function ViewRepository per get la versione pubblicata corrente basata su versionId (proprio come la vecchia entity framework; mappata usata con getVersion ()). Funzionerebbe, ma è un overhead più interno, perché farebbe due query … o Doctrine sarà abbastanza intelligente da ottimizzare questo, proprio come ha fatto con getVersion ().

NOTA: queste altre risposte non sono complete.

Riferimenti: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html http://doctrine-orm.readthedocs.org/en/2.0.x /reference/association-mapping.html#one-to-many-bidirectional

In genere, ho trovato l'approccio migliore è quello di risolvere questo in un modo diverso.

Uno schema comune che ho visto prima è usare una singola tabella per contenere tutti i record e avere un flag 'attivo'.

Se la tua query per select quella triggers funziona in questo modo:

 SELECT * FROM table WHERE active = true ORDER BY updated_at DESC LIMIT 1; 

Quindi abilitare uno nuovo diventa semplice come:

 UPDATE table SET active = 1, updated_at = '<timestamp>' WHERE id = <new id>; UPDATE table SET active = 0, updated_at = '<timestamp>' WHERE id = <old id>; 

La tua nuova pagina sarà triggers non appena la prima query avrà esito positivo e la tua seconda query eviterà qualsiasi stranezza in quanto quella row non sarà più triggers.

Se hai altri templates che dipendono da un ID coerente da referenziare, allora un'altra rotta che mantiene anche un certo equilibrio sarebbe avere una tabella per le voci attive (in toto, non in parte) e poi una seconda tabella con metadati aggiuntivi da tracciare versioni.

Quest'ultimo approccio potrebbe essere gestito in modo appropriato tramite il sistema di ereditarietà di Doctrine ( http://docs.doctrine-project.org/en/2.0.x/reference/inheritance-mapping.html ) che consente di definire la class View di base, e quindi per il model "ViewRevision", estendi Visualizza e aggiungi un timestamp di tipo "Revised on".

Secondo il consiglio di @jmather, ho deciso che questo model è "okay", perché ho bisogno di una singola entity framework; View a cui possano accedere altre entity framework; (es. Url di routing che puntano a una singola vista, cioè "pagina").

Ho modificato la relazione OneToOne per View solo come unidirezionale, perché ViewVersion ha già un'associazione alla View tramite l'altro OneToMany (quindi non ha bisogno di due routes indietro).

Questo mi permette di mantenere un metodo semplice per $ view-> getPublished () a portta di mano e sembra più logico.

 /** * @ORM\Entity * @ORM\Table(name="view") */ class View extends Entity\Base { /** * This is a OneToOne Unidirectional association, just so that we can get the * current published version easily, based on the publishedId. * @ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\TestVersion") * @ORM\JoinColumn(name="publishedId", referencedColumnName="id") */ protected $published; /** * @ORM\Column(type="integer", nullable=true) */ protected $publishedId = NULL; /** * This is the regular OneToMany Bi-Directional Association, for all the versions. * @ORM\OneToMany(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", mappedBy="view", cascade={"persist", "remove"}, orphanRemoval=true) */ protected $versions; } /** * @ORM\Entity * @ORM\Table(name="view_version") */ class ViewVersion extends Entity\Base { /** * @ORM\ManyToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", inversedBy="versions") * @ORM\JoinColumn(name="viewId", referencedColumnName="id") */ protected $view; /** * The primary view entity that this version belongs to. * @ORM\Column(type="integer", nullable=true) */ protected $viewId; } 

Tuttavia, ho scoperto che fino a quando $ view-> publishedId è impostato, la vista non può essere cancellata dal database a causa di vincoli di chiave esterna (anche se è unidirezionale). Quindi devo interrompere il collegamento a chiave esterna prima di rimuoverlo. Penso che vada bene. Ho pubblicato i dettagli su questo argomento : associazione di entity framework; sovrapposte che causa errori di vincolo di chiave esterna del database quando si rimuove l'entity framework;