web-dev-qa-db-ja.com

Symfony2 Doctrine2のオプションの一対一のリレーションに関するトラブル

Symfony2のDoctrine2と2つの関連エンティティに問題があります。

can(必須ではない)バイオグラフィーなどの情報を含むusermeta-entityを参照するユーザーエンティティがあります。

ユーザーは別のシステムによってインポートされるため、usermetaはオプションです。usermetaはアプリケーションで管理されます。

もちろん、両方を一緒に保存したいので、ユーザーを保存するには、ユーザーメタエンティティを作成または更新する必要があります。

両方ともaduseridという名前の列(両方のテーブルで同じ名前)で結合されています。

Usermetaがオプションの参照である場合、この場合の所有側はusermetaである必要があります。そうでない場合、doctrineはユーザーをロードし、usermetaエンティティを必要とします。

User-> setMeta。のコメントに注意してください。

/**
 * User
 *
 * @ORM\Table(name="user")
 * @ORM\Entity
 */
class User
{
/**
 * @var Usermeta
 * @ORM\OneToOne(targetEntity="Usermeta", mappedBy="user", cascade={"persist"})
 */
protected $meta;

public function getMeta()
{
    return $this->meta;
}

/**
 * 
 * @param Usermeta $metaValue 
 */
public function setMeta($metaValue)
{        
// I've tried setting the join-column-value here 
//  - but it's not getting persisted
// $metaValue->setAduserid($this->getAduserid());

// Then I've tried to set the user-object in Usermeta - but then 
//  it seems like Doctrine wants to update Usermeta and searches
//  for ValId names aduserid (in BasicEntityPersister->_prepareUpdateData) 
//  but only id is given -  so not luck here
// $metaValue->setUser($this);           

    $this->meta = $metaValue;
}

/**
 * @var integer
 *
 * @ORM\Column(name="rowid", type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $id;


/**
 * Get rowid
 *
 * @return integer 
 */
public function getId()
{
    return $this->id;
}

/**
 * @var integer
 *
 * @ORM\Column(name="ADuserid", type="integer", nullable=false)
 */
private $aduserid;

/**
 * Set aduserid
 *
 * @param integer $aduserid
 * @return User
 */
public function setAduserid($aduserid)
{
    $this->aduserid = $aduserid;

    return $this;
}

/**
 * Get aduserid
 *
 * @return integer 
 */
public function getAduserid()
{
    return $this->aduserid;
}

// some mor fields.... 
}

そして、Usermetaクラス:

/**
 * Usermeta
 *
 * @ORM\Table(name="userMeta")
 * @ORM\Entity
 */
class Usermeta
{
/**
 * @ORM\OneToOne(targetEntity="User", inversedBy="meta")
 * @ORM\JoinColumn(name="ADuserid", referencedColumnName="ADuserid")
 */
protected $user;

public function getUser()
{
    return $this->$user;
}    

public function setUser($userObj)
{
    $this->user = $userObj;
}

/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $id;

/**
 * @var integer
 *
 * @ORM\Column(name="ADuserid", type="integer", nullable=false)
 */
private $aduserid;

/**
 * Set aduserid
 *
 * @param integer $aduserid
 * @return User
 */
public function setAduserid($aduserid)
{
    $this->aduserid = $aduserid;

    return $this;
}

/**
 * Get aduserid
 *
 * @return integer 
 */
public function getAduserid()
{
    return $this->aduserid;
}
}

コントローラコードは次のようになります。

...

$userForm->bind($request);

    if($userForm->isValid()) {
        $em->persist($user);
        $em->flush();
    }
...
22
daluq

Zdenek Machekコメントはほぼ正しいです。 Doctrine2のドキュメントからわかるように、nullableオプションは結合アノテーション(@ JoinColumn)、マッピング1(@ OneToOne)ではありません。

@ JoinColumn doc:

この注釈は、@ ManyToOne、@ OneToOneフィールドの関係のコンテキスト、および@ManyToMany内にネストされた@JoinTableのコンテキストで使用されます。この注釈は必須ではありません。指定されていない場合、属性名とreferencedColumnNameはテーブル名とプライマリキー名から推測されます。

必須属性:

name:このリレーションの外部キー識別子を保持する列名。 @JoinTableのコンテキストでは、結合テーブルの列名を指定します。

referencedColumnName:この関係の結合に使用される主キー識別子の名前。

オプションの属性:

unique:影響を受けるエンティティ間でこの関係が排他的であり、データベース制約レベルで強制される必要があるかどうかを決定します。デフォルトはfalseです。

nullable:関連するエンティティが必要かどうか、またはnullが関係に許可された状態であるかどうかを判断します。デフォルトはtrueです。

onDelete:カスケードアクション(データベースレベル)

onUpdate:カスケードアクション(データベースレベル)

columnDefinition:列名の後に始まり、完全な(移植不可能な!)列定義を指定するDDL SQLスニペット。この属性により、高度なRMDBS機能を利用できます。 NULL/NOT NULLデフォルトなど、列を結合するためにわずかに異なる列定義が必要な場合は、@ JoinColumnでこの属性を使用する必要があります。ただし、デフォルトでは、@ Columnの「columnDefinition」属性は、関連する@JoinColumnのcolumnDefinitionも設定します。これは、外部キーを機能させるために必要です。

http://doctrine-orm.readthedocs.org/en/latest/reference/annotations-reference.html#annref-joincolumn

@ OneToOne doc:

@OneToOneアノテーションは、指定可能なオプションが1つ追加された@ManyToOneとほぼ同じように機能します。ターゲットエンティティテーブルを使用する@JoinColumnの構成のデフォルトと、主キー列名もここに適用されます。

必須属性:

targetEntity:参照されるターゲットエンティティのFQCN。両方のクラスが同じネームスペースにある場合、非修飾クラス名にすることができます。重要:先行するバックスラッシュはありません!

オプションの属性:

cascade:カスケードオプション

fetch:LAZYまたはEAGERのいずれか

orphanRemoval:孤立したインスタンス、所有インスタンスに接続されていない逆OneToOneエンティティをDoctrineで削除するかどうかを指定するブール値。デフォルトはfalseです。

inversedBy:inversedBy属性は、関係の逆側であるエンティティ内のフィールドを指定します。

http://doctrine-orm.readthedocs.org/en/latest/reference/annotations-reference.html#onetoone

16

問題に対して間違ったタイプの関係を使用しています。

欲しいのは 単方向の一対一 fromUsermetatoUser

双方向の1対1の関係とは、次のことを意味します。

  1. ユーザーにはUsermetaオブジェクトが必要です。
  2. UsermetaオブジェクトにはUserが必要です。

あなたのケースでは、2番目の条件のみを要求しようとしています。

これは、UsermetaからUserにのみハイドレートできることを意味し、逆にはできません。

残念ながらdoctrine ゼロまたは1対多をサポートしていません 関係。

8
james_t

この非常に遅い回答を提出することで誰にも邪魔されないことを願っていますが、この問題を解決する方法は次のとおりです。

/**
 * @var Takeabyte\GripBundle\Entity\PDF
 * @ORM\OneToOne(targetEntity="Takeabyte\GripBundle\Entity\PDF", inversedBy="element", fetch="EAGER", orphanRemoval=true)
 */
protected $pdf = null;

追加した = null;属性宣言に。これを読んでいる人にとってこれが助けになることを願っています。

0
Rick Slinkman

エラーメッセージが表示されました"spl_object_hash()はパラメーター1がオブジェクトであると想定し、nullが..."同じことを試みています。双方向のOne to One関係を定義しようとしましたが、逆の値はnullになります。これにより、エラーメッセージが表示されました。関係の逆側を取り除くことで問題は解決しました。 Zero or One to One関係がサポートされていないのは残念です。

0
Wilt