2015-05-22 7 views
5

Mam User i UserProfile Jednostki ORM związane z Doktorem OneToOne. Powinny zawsze istnieć jako para, nie powinno być User bez UserProfile.Doctrine OneToOne tożsamość poprzez wyjątek podmiotu zagranicznego w przypadku Flush

Użytkownik powinien otrzymać swój identyfikator z autorejestracji, podczas gdy UserProfile powinien mieć identyfikator użytkownika. Tak więc oba powinny mieć ten sam identyfikator i nie ma innej kolumny do ustawienia relacji (Doctrine docs: Identity through foreign Entities).

Identyfikator UserProfile jest jednocześnie kluczem podstawowym (PK) i kluczem obcym (FK).

Udało mi się to skonfigurować, ale wymaga to, aby Użytkownik został zapisany jako pierwszy i dopiero później UserProfile został utworzony i zapisany w oddzielnym kroku.

Co chcę jest, że UserProfile jest zawsze tworzona z Użytkownikiem, w konstruktorze, ale jeśli to zrobię, otrzymuję ten wyjątek:

Doctrine\ORM\ORMInvalidArgumentException: The given entity of type 'AppBundle\Entity\UserProfile' (AppBundle\Entity\[email protected]) has no identity/no id values set. It cannot be added to the identity map.

Proszę zobaczyć kod poniżej - to działa, ale nie tak jak chcę. Komentarze php pokazują, co chcę osiągnąć.

Test.php:

/** 
* It works, both saving and loading. 
* BUT, it requires that I create and save UserProfile 
* in a separate step than saving User step. 
*/ 

// create and save User 
$user = new User(); 
$objectManager->persist($user); 
$objectManager->flush(); 

// create and save UserProfile (this should be unnecessary) 
$user->createProfile() 
$objectManager->flush(); 

User.php:

use Doctrine\ORM\Mapping as ORM; 

/** 
* @ORM\Entity(repositoryClass="AppBundle\Entity\UserRepository") 
* @ORM\Table(name="users") 
*/ 
class User 
{ 
    /** 
    * @var int 
    * 
    * @ORM\Column(name="uid", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * It's NULL at first, I create it later (after saving User). 
    * 
    * @var UserProfile|null 
    * 
    * @ORM\OneToOne(targetEntity="UserProfile", mappedBy="user", cascade="persist") 
    */ 
    private $profile = null; 

    public function __construct() 
    { 
     // I want to create UserProfile inside User's constructor, 
     // so that it is always present (never NULL): 
     //$this->profile = new UserProfile($this); 

     // but this would give me error: 
     // 
     // Doctrine\ORM\ORMInvalidArgumentException: 
     // The given entity of type 'AppBundle\Entity\UserProfile' 
     // (AppBundle\Entity\[email protected]) 
     // has no identity/no id values set. It cannot be added to the identity map. 
    } 

    public function createProfile() 
    { 
     $this->profile = new UserProfile($this); 
    } 
} 

UserProfile.php:

use Doctrine\ORM\Mapping as ORM; 

/** 
* @ORM\Entity 
* @ORM\Table(name="profiles") 
*/ 
class UserProfile 
{ 
    /** 
    * – UserProfile's "uid" column points to User's "uid" column 
    * – it is PK (primary key) 
    * - it is FK (foreign key) as well 
    * – "owning side" 
    * 
    * @var User 
    * 
    * @ORM\Id 
    * @ORM\OneToOne(targetEntity="User", inversedBy="profile") 
    * @ORM\JoinColumn(name="uid", referencedColumnName="uid", nullable=false) 
    */ 
    private $user; 

    public function __construct(User $user) 
    { 
     $this->user = $user; 
    }  
} 

aplikacja testu: https://github.com/MacDada/DoctrineOneToOneTest

+0

Id jest rzeczą bazową i nie powinno stanowić problemu w modelu. Porzuć pogląd, że potrzebują tej samej wartości klucza głównego. A jeśli to nie zadziała, generuj rezygnację z tego, że trzeba być automatycznym, a drugi nie. – Cerad

+0

@Cerad Buduję na bazie starszej aplikacji - baza danych jest tym, czym jest. Muszę dostosować Doctrine do aktualnego schematu, a nie odwrotnie ... Plus, powyższy kod działa. Doctrine może obsługiwać klucze obce będące kluczami podstawowymi. Po prostu nie może utrzymywać jednostek w jednym kolorze. A przynajmniej szukam odpowiedzi, jak skonfigurować Doctrine, aby mogła. – MacDada

+0

Wystarczająco fair. Jeśli przeprowadzisz wyszukiwanie, znajdziesz kilkaset odmian tego samego pytania. Wszyscy z tą samą odpowiedzią. – Cerad

Odpowiedz

1

Należy pamiętać, że rzeczywisty obiekt musi zostać zapisany przez EntityManager. Samo podanie klasy jako odniesienia do innej klasy nie powoduje, że jednostka entityager jest świadoma faktu, że obie klasy istnieją.

Powinieneś utrzymywać rzeczywisty profil UserProf do EntityManager, aby móc zapisać relację.

UPDATE z powodu negatywnego komentarza:

Proszę przeczytać docs Doktryna ... Należy utrzymywać!

Poniższy przykład stanowi rozszerzenie przykładu komentarza użytkownika tego rozdziału. Załóżmy, że w naszej aplikacji użytkownik jest tworzony za każdym razem, gdy napisze swój pierwszy komentarz. W tym przypadku możemy użyć następującego kodu:

<?php 
$user = new User(); 
$myFirstComment = new Comment(); 
$user->addComment($myFirstComment); 

$em->persist($user); 
$em->persist($myFirstComment); 
$em->flush(); 

Nawet jeśli utrzymują się nowego użytkownika, który zawiera nasz nowy komentarz ten kod będzie zawodzić, jeśli usunięto wezwanie do EntityManager # utrzymują ($ myFirstComment). Doctrine 2 nie kaskaduje operacji persist do wszystkich nowo zagnieżdżonych encji, które również są nowe.

Aktualizacja2: Rozumiem, co chcesz osiągnąć, ale zgodnie z projektem nie powinieneś przenosić tej logiki w swoje istoty. Jednostki powinny reprezentować mniej logiki, jak to możliwe, ponieważ reprezentują twój modalny.

Have powiedział, że wierzę, można osiągnąć to, co staramy się robić to tak:

$user = new User(); 
$profile = $user->getProfile(); 
$objectManager->persist($user); 
$objectManager->persist($profile); 
$objectManager->flush(); 

Należy jednak rozważyć utworzenie userService zawierający EntityManager i sprawiają, że odpowiedzialny za tworzenie, łączenie i przechowując user + userProfile entity.

+0

Nie, profil jest dopasowywany, aby go utrwalić dzięki 'cascade =" persist "'. Jeśli usunę go i utrzymuję profil "ręcznie", problem będzie nadal występował. – MacDada

+0

Przeczytaj Doktryny docs ... – Armand

+0

To nie pomaga, już to wypróbowałem (jeszcze jeden raz, teraz, aby być całkowicie pewnym). Ten sam błąd. – MacDada

Powiązane problemy