1

所有しているサブオブジェクトを保持してオブジェクトを作成するのに問題があります。具体的には、少なくとも 1 つの PGPKey オブジェクトを所有する User クラスがあります。

次のコード スニペットは失敗します。

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

エラーで:

SQLSTATE [23000]: 整合性制約違反: 1048 列 'PGPKeys.owner' を null にすることはできません

私にとっての問題は次のとおりです。 PGPKey.owner に対応する User.idUser フィールドは GeneratedValue であるため、persist が呼び出された時点ではまだ定義されていません。次に、Doctrine は最初に PGPKey を保存しようとしますが、SQL は所有者が null であることを許可しません。ユーザーが最初に保存される場合、生成された 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 に答える