2013-04-01 13 views
21

Ho un problema con Doctrine2 in Symfony2 e due entità correlate.Problema di symfony2 Doctrine2 con relazione uno a uno opzionale

Ci

è un facile da entità che può (non deve) avere un'usermeta-entità di riferimento, che contiene informazioni come la biografia ecc

L'usermeta è facoltativa perché l'utente viene importato da un altro sistema, mentre è usermeta gestito nella mia applicazione.

Ovviamente voglio salvare entrambi insieme, in modo che il salvataggio di un utente debba creare o aggiornare un'entità usermeta.

Entrambi sono uniti da una colonna denominata aduserid (stesso nome in entrambe le tabelle).

Ho riconosciuto che se usermeta è un riferimento facoltativo il proprietario in questo caso deve essere usermeta, altrimenti la doctrina carica l'utente e ha bisogno dell'entità usermeta, ma non sempre è lì.

Si prega di notare i commenti in User-> setMeta ..

/** 
* User 
* 
* @ORM\Table(name="user") 
* @ORM\Entity 
*/ 
class User 
{ 
/** 
* @var Usermeta 
* @ORM\OneToOne(targetEntity="Usermeta", mappedBy="user", cascade={"persist"}) 
*/ 
protected $meta; 

public function getMeta() 
{ 
    return $this->meta; 
} 

/** 
* 
* @param Usermeta $metaValue 
*/ 
public function setMeta($metaValue) 
{   
// I've tried setting the join-column-value here 
// - but it's not getting persisted 
// $metaValue->setAduserid($this->getAduserid()); 

// Then I've tried to set the user-object in Usermeta - but then 
// it seems like Doctrine wants to update Usermeta and searches 
// for ValId names aduserid (in BasicEntityPersister->_prepareUpdateData) 
// but only id is given - so not luck here 
// $metaValue->setUser($this);   

    $this->meta = $metaValue; 
} 

/** 
* @var integer 
* 
* @ORM\Column(name="rowid", type="integer", nullable=false) 
* @ORM\Id 
* @ORM\GeneratedValue(strategy="IDENTITY") 
*/ 
private $id; 


/** 
* Get rowid 
* 
* @return integer 
*/ 
public function getId() 
{ 
    return $this->id; 
} 

/** 
* @var integer 
* 
* @ORM\Column(name="ADuserid", type="integer", nullable=false) 
*/ 
private $aduserid; 

/** 
* Set aduserid 
* 
* @param integer $aduserid 
* @return User 
*/ 
public function setAduserid($aduserid) 
{ 
    $this->aduserid = $aduserid; 

    return $this; 
} 

/** 
* Get aduserid 
* 
* @return integer 
*/ 
public function getAduserid() 
{ 
    return $this->aduserid; 
} 

// some mor fields.... 
} 

e la classe Usermeta:

/** 
* Usermeta 
* 
* @ORM\Table(name="userMeta") 
* @ORM\Entity 
*/ 
class Usermeta 
{ 
/** 
* @ORM\OneToOne(targetEntity="User", inversedBy="meta") 
* @ORM\JoinColumn(name="ADuserid", referencedColumnName="ADuserid") 
*/ 
protected $user; 

public function getUser() 
{ 
    return $this->$user; 
}  

public function setUser($userObj) 
{ 
    $this->user = $userObj; 
} 

/** 
* @var integer 
* 
* @ORM\Column(name="id", type="integer", nullable=false) 
* @ORM\Id 
* @ORM\GeneratedValue(strategy="IDENTITY") 
*/ 
private $id; 

/** 
* @var integer 
* 
* @ORM\Column(name="ADuserid", type="integer", nullable=false) 
*/ 
private $aduserid; 

/** 
* Set aduserid 
* 
* @param integer $aduserid 
* @return User 
*/ 
public function setAduserid($aduserid) 
{ 
    $this->aduserid = $aduserid; 

    return $this; 
} 

/** 
* Get aduserid 
* 
* @return integer 
*/ 
public function getAduserid() 
{ 
    return $this->aduserid; 
} 
} 

il codice di controllo si presenta così:

... 

$userForm->bind($request); 

    if($userForm->isValid()) { 
     $em->persist($user); 
     $em->flush(); 
    } 
... 
+0

non è il trucco per impostare meta - annullabile = true /** * @var Usermeta * @ORM \ OnetoOne (targetEntity = "Usermeta", mappedBy = "user" , cascade = {"persist"}, nullable = true) */ protetto $ meta; –

+1

@Zdenek, l'annotazione OneToOne non ha parametri nullable. È un parametro di '@ JoinColumn'. – Athlan

risposta

-4

Leggendo la mia vecchia domanda è abbastanza divertente da quando vedo il problema a prima vista ora ..

quando si trattava di una soluzione che ho pensato che la dottrina può gestire solo Ids di nome "id", ma. .. l'aduserid non è solo contrassegnato come ID, manca l'annotazione Id e la dottrina non può usare i campi per la colonna di join ..

Seconda cosa, Zdenek Machek aveva ragione: deve essere contrassegnato come nullable.

7

You' ri usando il tipo sbagliato di Relazione per il tuo problema.

quello che vuoi è un unidirectional one to one da Usermeta a utente.

Un'unica bidirezionale ad una relazione significherebbe seguente:

  1. un utente deve avere un oggetto Usermeta.
  2. Un oggetto Usermeta DEVE avere un utente.

Nel tuo caso stai solo cercando di richiedere la seconda condizione.

Ciò significa che puoi solo idratare Utente da Usermeta e non viceversa.

Purtroppo relazioni does not support Zero or One to Many.

0

Ho ricevuto il messaggio di errore "spl_object_hash() si aspetta che il parametro 1 sia oggetto, null dato in ..." mentre si prova la stessa cosa.Ho provato a definire una relazione bidirezionale One to One mentre il valore inverso potrebbe essere null. Questo ha dato il messaggio di errore. Portare via il lato inverso della relazione ha risolto il problema. È un peccato che le relazioni Zero or One to One non siano supportate.

0

Spero di non disturbare chiunque presentando questa risposta molto tardi, ma ecco come ho risolto questo problema:

/** 
* @var Takeabyte\GripBundle\Entity\PDF 
* @ORM\OneToOne(targetEntity="Takeabyte\GripBundle\Entity\PDF", inversedBy="element", fetch="EAGER", orphanRemoval=true) 
*/ 
protected $pdf = null; 

ho aggiunto = null; alla dichiarazione di attributo. Spero che questo sia di qualche aiuto per chiunque legga questo.

+2

Il valore predefinito di qualsiasi campo classe è nullo in ogni caso. –

14

Il Zdenek Machek il commento è quasi corretto. Come si può vedere dalla documentazione di Doctrine2, l'opzione nullable dovrebbe essere nell'annotazione del join (@JoinColumn), non nel mapping (@OneToOne).

@JoinColumn doc:

Questa annotazione viene utilizzato nel contesto delle relazioni in @ManyToOne, campi @OneToOne e nel contesto della @JoinTable nidificato all'interno di un @ManyToMany. Questa annotazione non è richiesta. Se non specificato, il nome degli attributi e referencedColumnName vengono dedotti dai nomi delle tabelle e delle chiavi primarie. attribuisce

richiesto:

nome: Nome della colonna che contiene l'identificatore chiave esterna per questa relazione. Nel contesto di @JoinTable specifica il nome della colonna nella tabella di join.

referencedColumnName: nome dell'identificatore chiave principale utilizzato per l'unione di questa relazione.

attributi opzionali:

unico: determina se questo rapporto esclusivo tra le entità e interessata deve essere applicata in modo a livello di vincolo di database. Il valore predefinito è falso.

nullable: determinare se è richiesta l'entità correlata o se null è uno stato consentito per la relazione. Il valore predefinito è true.

onDelete: Cascade Azione (a livello di database)

onUpdate: Cascade Azione (a livello di database)

ColumnDefinition: DDL SQL frammento che inizia dopo il nome della colonna e specifica la definizione di colonna completa (non portatile!). Questo attributo consente di utilizzare funzioni RMDBS avanzate. L'utilizzo di questo attributo su @JoinColumn è necessario se hai bisogno di definizioni di colonne leggermente diverse per unire le colonne, ad esempio per quanto riguarda i valori NULL/NOT NULL. Tuttavia, per impostazione predefinita, l'attributo "columnDefinition" in @Column imposta anche la colonnaDefinizione relativa di @ JoinColumn.Questo è necessario per far funzionare le chiavi esterne.

http://doctrine-orm.readthedocs.org/en/latest/reference/annotations-reference.html#annref-joincolumn

@OneToOne doc:

L'annotazione @OneToOne funziona quasi esattamente come la @ManyToOne con un'opzione aggiuntiva che può essere specificato. Anche qui si applicano le impostazioni di configurazione per @JoinColumn utilizzando la tabella delle entità di destinazione e i nomi delle colonne delle chiavi primarie.

Attributi obbligatori:

targetEntity: FQCN dell'entità di destinazione di riferimento. Può essere il nome della classe non qualificato se entrambe le classi si trovano nello stesso spazio dei nomi. IMPORTANTE: nessuna barra rovesciata iniziale!

attributi opzionali:

cascata: Cascade Opzione

fetch: Uno dei pigri o EAGER

orphanRemoval: booleano che specifica se orfani, inverse entità OnetoOne che non sono collegati a nessuna istanza proprietaria, devono essere rimossi da Doctrine. Il valore predefinito è falso.

inverso con: l'attributo inversedBy indica il campo nell'entità che è il lato inverso della relazione.

http://doctrine-orm.readthedocs.org/en/latest/reference/annotations-reference.html#onetoone

Problemi correlati