我在使用拥有的子对象持久化和对象时遇到了一些麻烦。更具体地说,我有一个User类,它拥有至少一个PGPKey对象。
以下代码段失败:
$user = new User("username","password");
$em->persist($user);
错误:
SQLSTATE [23000]:完整性约束违规:1048列'PGPKeys.owner'不能为空
给我的问题如下: User.idUser字段对应于PGPKey.owner是GeneratedValue,因此在调用persist时仍未定义。然后Doctrine首先尝试保存PGPKey,但SQL不允许所有者为null。如果首先保存用户,则可以使用生成的id保存到PGPkey的owner字段。
我原本以为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;
}
}
答案 0 :(得分: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。这样,用户首先存储到数据库,给定一个自动id,并在执行时将此id传递给PGPKey子对象
$user = new User("username","password");
$em->persist($user)
希望这也有助于其他人。