Ho alcune entiti con relazioni e attributi comuni. Quindi, voglio semplificare il mio schema usando la mappatura ereditaria.Molti-a-uno, auto-referenziamento con mappatura dell'ereditarietà
Ho creato un BaseData mappedsuperclass e le mie altre entità lo espandono. Questa classe BaseData ha le relazioni comuni di cui ho bisogno in ogni entità.
Funziona con molti-a-uno relazione, come
/**
* @ORM\MappedSuperclass
*/
class BaseData
{
/**
* @ORM\ManyToOne(targetEntity="Service")
* @ORM\JoinColumn(name="service_id", referencedColumnName="id")
*/
protected $service;
Ma diventa un po 'più complicato con autoreferenziale.
Per esempio, dal momento che voglio creare un riferimento genitore, ho provato:
/**
* @ORM\MappedSuperclass
*/
class BaseData
{
/**
* @ORM\ManyToOne(targetEntity="BaseData")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id", nullable=true)
*/
protected $parent;
Ovviamente, portano a un TableNotFoundException quando cerco di interrogare questa entità: QLSTATE[42S02]: Base table or view not found: 1146 Table 'project.base_data' doesn't exist
.
Quindi, ho provato AssociationOverrides, ma sembra che non consenta di modificare l'entità di destinazione.
Quindi, c'è un modo per creare qualche riferimento su una MappedSuperclass? E a proposito, ha senso?
Molte grazie in anticipo!
Aggiornamento
Ecco l'anwser:
ho definito il protected $parent
e protected $children
nel mio BaseData mappedSuperClass come previsto. Li ho annotati con altre informazioni di cui ho bisogno. ad esempio:
/**
* @ORM\MappedSuperclass
*/
class BaseData
{
/**
* @Datagrid\Column(field="parent.id", title="datagrid.parent_id", visible=false, safe=false)
* @Serializer\Expose
* @Serializer\Groups({"foo"})
*/
protected $parent;
/**
* @Serializer\Expose
* @Serializer\Groups({"elastica"})
*/
protected $children;
Poi, aggiungo il rapporto ORM con l'evento loadClassMetadata.
/**
* @param LoadClassMetadataEventArgs $eventArgs
*/
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
// the $metadata is all the mapping info for this class
$classMetadata = $eventArgs->getClassMetadata();
$reflObj = new \ReflectionClass($classMetadata->name);
if($reflObj) {
if ($reflObj->isSubclassOf('CoreBundle\Entity\BaseData')) {
$fieldMapping = array(
'targetEntity' => $classMetadata->name,
'fieldName' => 'parent',
'inversedBy' => 'children',
'JoinColumn' => array(
'name' => 'parent_id',
'referencedColumnName' => 'id',
'nullable' => true,
'onDelete' => 'SET NULL',
),
);
$classMetadata->mapManyToOne($fieldMapping);
$fieldMapping = array(
'fieldName' => 'children',
'targetEntity' => $classMetadata->name,
'mappedBy' => 'parent',
);
$classMetadata->mapOneToMany($fieldMapping);
}
}
}
Registrare l'evento, e il gioco è fatto.
Ora, ogni classe che estende la superClass BaseData ottiene la relazione. Per esempio, php app/console doctrine:generate:entities MyBundle
volontà genera il seguente codice all'interno dell'ente SubClass:
/**
* Set parent
*
* @param \MyBundle\Entity\Subclass $parent
*
* @return Subclass
*/
public function setParent(\MyBundle\Entity\Subclass $parent = null)
{
$this->parent = $parent;
return $this;
}
/**
* Get parent
*
* @return \MyBundle\Entity\Subclass
*/
public function getParent()
{
return $this->parent;
}
/**
* Add child
*
* @param \MyBundle\Entity\Subclass $child
*
* @return Subclass
*/
public function addChild(\MyBundle\Entity\Subclass $child)
{
$this->children[] = $child;
return $this;
}
/**
* Remove child
*
* @param \MyBundle\Entity\Subclass $child
*/
public function removeChild(\MyBundle\Entity\Subclass $child)
{
$this->children->removeElement($child);
}
/**
* Get children
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getChildren()
{
return $this->children;
}
Si potrebbe fare di sé solo come riferimento per le classi figlio come MappedSupperclass non è di per sé un'entità. Dalla documentazione: Una superclasse mappata non può essere un'entità, non è interrogabile e le relazioni persistenti definite da una superclasse mappata devono essere unidirezionali (con una sola parte proprietaria). Ciò significa che le associazioni One-To-Many non sono possibili su una superclasse mappata.Inoltre, le associazioni da molti a molti sono possibili solo se la superclasse mappata viene utilizzata solo in una sola entità al momento. –
L'ho indovinato, ma il mio obiettivo era quello di rendere l'autoreferenzialità che funziona per ogni classe di figlio. Voglio dire, scrivendo 'targetEntity =" BaseData "', speravo che ogni classe figlia usasse il proprio nome. Quindi, suppongo, devo fare manualmente l'auto-referenza del genitore in ogni classe figlia, non è vero? E grazie per il vostro aiuto. – TiPi
Nessun problema! Come @MappedSuperclass non è un'entità in sé, sì, immagino, si può fare solo nelle classi figlie. post scriptum IMHO, @MappedSuperclass è molto utile per tutti i tipi di dizionari - nell'ultimo progetto, ad esempio, avevo un BaseDictionaryDocument, con due campi id e sysName. E tutti i dizionari sembravano semplicemente "classe BlahBlahDocument estende BaseDictionaryDocument {}" e, naturalmente, un'annotazione con nome tabella/raccolta in alto. –