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
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
@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
Wystarczająco fair. Jeśli przeprowadzisz wyszukiwanie, znajdziesz kilkaset odmian tego samego pytania. Wszyscy z tą samą odpowiedzią. – Cerad