2015-05-22 10 views
5

üzerinde yabancı varlık istisnası üzerinden User ve UserProfile OneToOne ile ilgili Doctrine ORM varlıkları var. Her zaman bir çift olarak var olmalı, UserProfile olmadan User olmalıdır.Doctrine OneToOne kimliği

UserProfile kullanıcının kimliğine sahipken, kullanıcının kimliğini autoincrement'ten alması gerekir. Yani her ikisi de aynı kimliğe sahip olmalı ve ilişkiyi kurmak için başka bir sütun yoktur (Doctrine docs: Identity through foreign Entities).

UserProfile'ın kimliği, aynı anda hem birincil anahtar (PK) hem de yabancı anahtar (FK) 'dir.

Ayarlamayı başardım, ancak önce Kullanıcı'nın kaydedilmesini ve daha sonra UserProfile oluşturulmasını ve ayrı bir adımda kaydedilmesini gerektirir.

İstediğim UserProfile hep yapıcı içinde, Kullanıcı ile oluşturulduğunu, ancak bunu yaparsanız, bu durum almak:

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.

kod aşağıda görebilirsiniz - çalıştığını, ancak istediğim gibi. Php yorumları ne elde etmek istediğimi gösterir.

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; 
    }  
} 

test uygulaması: https://github.com/MacDada/DoctrineOneToOneTest

+0

Id bir veritabanı nesnesidir ve modelinizde bir endişe olmamalıdır. Aynı birincil anahtar değere ihtiyaçları olduğu fikrinden vazgeç. Ya da başarısız olursa, birinin otomatik olması ve diğerinin olmaması gerektiği fikrini ortaya çıkar. – Cerad

+0

@Cerad Eski bir uygulama üzerinde yapıyorum - veritabanı nedir. Şu anki şemaya Doktrini ayarlamalıyım, tersi değil… Artı, yukarıdaki kod çalışır. Doktrin, birincil anahtarlar olan yabancı anahtarları işleyebilir. Sadece bir sifondaki varlıkları devam ettiremez. Ya da en azından cevabı arıyorum, doktrini nasıl yapılandırabilsin diye. – MacDada

+0

Yeterince adil. Eğer bir arama yaparsanız, aynı sorunun birkaç yüz varyasyonunu bulacaksınız. Hepsi aynı cevapla. – Cerad

cevap

1

Lütfen gerçek nesnenin EntityManager tarafından kaydedilmesi gerektiğini unutmayın. Sınıfı diğer sınıfa referans olarak vermek, entityManager öğesinin her iki sınıfın varlığından haberdar olmasını sağlamaz.

İlişkisini kaydedebilmek için asıl userProfile EntityManager'a devam etmelisiniz. Çünkü negatif yorum

GÜNCELLEME:

Doktrini dokümanlar okuyunuz ... Sen devam etmelidir!

Aşağıdaki örnek, bu bölümün Kullanıcı-Yorum örneğinin bir uzantısıdır. Uygulamasında, ilk yorumunu yazdığı zaman bir kullanıcının oluşturulduğunu varsayalım.

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

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

Eğer EntityManager # çağrısına devam etmesi ($ myFirstComment) kaldırıldığını, bu kod başarısız olur yeni Comment içeren yeni Kullanıcının inat bile: Bu durumda, aşağıdaki kodu kullanabilirsiniz. Doktrin 2, devam eden çalışmayı, aynı zamanda yeni olan tüm iç içe geçmiş varlıklara dayandırmaz.

Update2: Ben bunu başarmak isteyen, ancak tasarımdan size varlıklar içinde bu mantık hareket etmemelidir ne olduğunu anlamak. Varlıklar, modalınızı temsil ettikleri için mümkün olduğunca az mantık göstermelidir.sözü

Have, sana böyle yapmaya çalıştığımız şeyi başarabileceğimizi inanıyoruz:

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

Bununla birlikte EntityManager içeren bir userService oluşturmayı düşünün ve oluşturma, bağlama ve devam eden söz konusu sorumlu yapmalıdır user + userProfile öğesi.

+0

Nope, "cascade =" persist "' sayesinde profilin kalıcı olması için eşleştirildi. Onu kaldırırsam ve profili "el ile" sürdürürsem, sorun hala devam eder. – MacDada

+0

Lütfen doktrin belgelerini okuyun ... – Armand

+0

Bu yardımcı olmadı, bunu zaten denedim (şimdi bir kez daha, tam olarak emin olmak için). Aynı hata. – MacDada