2012-10-24 30 views
1

我有一些麻煩來堅持和擁有一個擁有子對象的對象。更具體地說,我有一個擁有至少一個PGPKey對象的用戶類。 與OneToMany關係的主體級聯到子對象

下面的代碼段失敗:

$user = new User("username","password"); 
$em->persist($user); 

與錯誤:

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'PGPKeys.owner' cannot be null

問題的方案爲了我如下: 的User.idUser字段,其對應於PGPKey。 owner是一個GeneratedValue,因此在調用persist時仍未定義。然後Doctrine首先嚐試保存PGPKey,但SQL不允許所有者爲空。如果用戶首先被保存,則生成的ID可以用於保存到PGPkey的所有者字段。

我本來料想到Doctrine在歸屬之前就保存了擁有的對象,但似乎並非如此,或者我錯過了某些東西。

User.postPersist()永遠不會執行。

user.php的

/** 
* @HasLifecycleCallbacks 
* @Entity 
*/ 
class user { 
    /** 
    * @Id 
    * @Column(type="integer", nullable=false, columnDefinition="int(11) unsigned NOT NULL AUTO_INCREMENT"); 
    * @GeneratedValue(strategy="AUTO") 
    */ 
    protected $idUser; 

    /** 
    * @Column(type="string", nullable=false, columnDefinition="VARCHAR(255) NOT NULL") 
    */ 
    protected $username; 

    /** 
    * @OneToMany(targetEntity="PGPKey", mappedBy="owner", cascade={"persist","remove"}, orphanRemoval=true) 
    * @var PGPKey[] 
    */ 
    protected $PGPKeys; 

    public function __construct($username,$password) 
    { 
     $this->PGPKeys = new ArrayCollection(); 
     $this->username = $username; 
     $this->setPassword($password); 
    } 

    /** @PostPersist */ 
    public function postPersist(){ 
     foreach ($this->PGPKeys as $key) 
     { 
      $key->setOwner($this->getId()); 
     } 
    } 
    public function setPassword($newPassword, $oldPassword = false) 
    { 
     if ($oldPassword === false || !count($this->PGPKeys)) 
     { 
      $newkey = new PGPKey($newPassword); 
      $newkey->setOwner($this->idUser); 
      $this->PGPKeys[] = $newkey; 
     } 
     else 
     { 
      $this->PGPKeys[count($this->PGPKeys) - 1]->changePassword($oldPassword, $newPassword); 
     } 
    } 
} 

PGPKey.php

/** 
* @Entity 
*/ 
class PGPKey 
{ 

    /** 
    * @Id 
    * @Column(type="integer", unique=true, columnDefinition="int(11) unsigned NOT NULL AUTO_INCREMENT"); 
    * @GeneratedValue(strategy="AUTO") 
    */ 
    protected $idKey; 

    /** 
    * @Column(type="integer", columnDefinition="int(11) unsigned NOT NULL"); 
    * @ManyToOne(targetEntity="User", inversedBy="PGPKeys"); 
    */ 
    protected $owner; 

    public function __construct($password) 
    { 
     //do RSA stuff 
    } 

    public function setOwner($ownerid) 
    { 
     $this->owner = $ownerid; 
     return $this; 
    } 
} 

回答

1

與他人學說IRC聊天后,我終於可以提出一個解決方案:

在課堂PGPKey代替

/** 
* @Column(type="integer", columnDefinition="int(11) unsigned NOT NULL"); 
* @ManyToOne(targetEntity="User", inversedBy="PGPKeys"); 
*/ 
protected $owner; 
public function setOwner($ownerid) 
{ 
    $this->owner = $ownerid; 
    return $this; 
} 

應改爲

/** 
* @var User 
* @ManyToOne(targetEntity="User", inversedBy="PGPKeys"); 
* @JoinColumn(name="owner", referencedColumnName="idUser") 
*/ 
protected $owner; 

public function setOwner(User $owner) 
{ 
    $this->owner = $owner; 
    return $this; 
} 

所以屬性必須被定義爲JoinColumn,你必須參照整個所有者對象,而不僅僅是ID。 Doctrine然後將使用JoinColumn註釋中的信息從用戶中提取id。執行

$user = new User("username","password"); 
$em->persist($user) 

希望這有助於其他人也當這樣,用戶首先被存儲到數據庫中,給定一個自動ID和該ID被傳遞給PGPKey子對象。