1

我在坚持和反对拥有子对象时遇到了一些麻烦。更具体地说,我有一个拥有至少一个 PGPKey 对象的用户类。

以下代码段失败:

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

出现错误:

SQLSTATE [23000]:违反完整性约束:1048 列 'PGPKeys.owner' 不能为空

对我来说问题如下:对应于 PGPKey.owner 的 User.idUser 字段是 GeneratedValue ,因此在调用 persist 时仍然未定义。然后 Doctrine 首先尝试保存 PGPKey 但 SQL 不允许 owner 为空。如果首先保存用户,则生成的 id 可用于保存到 PGPkey 的所有者字段。

我原以为 Doctrine 在拥有之前保存了拥有对象,但事实并非如此,或者我遗漏了一些东西。

User.postPersist() 永远不会执行。

用户.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;
    }
}
4

1 回答 1

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)

希望这对其他人也有帮助。

于 2012-10-25T18:40:53.690 回答