2013-04-09 14 views
5

は、私は私のデータベース(簡易版)で、以下の関連を持っています。複合キーとフォーム

私はフォームを投稿するとき、私は主にドキュメントからHow to Embed a Collection of Formsチュートリアルに触発された私は、私は1つの順位項目に必要な数の関係を追加すると同時に、それを作成することができ、フォーム(。

を持っています、 Doctrineは私がOneToMany関係にcascade={"persist"}オプションを持っているので、順番に関係Relationオブジェクトを永続化しようとするため、私はこのエラーを理解

Entity of type TEST\MyBundle\Entity\Relation has identity through a foreign entity TEST\MyBundle\Entity\Order, however this entity has no identity itself. You have to call EntityManager#persist() on the related entity and make sure that an identifier was generated before trying to persist 'TEST\MyBundle\Entity\Relation'. In case of Post Insert ID Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL) this means you have to call EntityManager#flush() between both persist operations.

しかし、どのように、私はこの動作を回避することができます:私は次のエラーを取得します。 ?

私はcascade={"persist"}を削除しようとしましたが、手動でエンティティを永続化しましたが、同じエラーが発生しました。(IDを取得するにはflush()を注文する必要があります。
私はflush()の前にdetach()Relationのオブジェクトを試しましたが、運がありません。

答えて

1

私は、Relationテーブルに分離されたプライマリキーを作成しました(コンポジットを持つ代わりに)。
これは汚れた修正のようですが、この状況を処理するにはより良い方法があると確信していますが、今のところうまくいきます。

/** 
* Relation 
* 
* @ORM\Entity 
*/ 
class Relation 
{ 
    /** 
    * @var integer 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @ORM\ManyToOne(targetEntity="Contact", inversedBy="relation") 
    */ 
    protected $contact; 

    /** 
    * @ORM\ManyToOne(targetEntity="Order", inversedBy="relation") 
    */ 
    protected $order; 

    /** 
    * @var integer 
    * 
    * @ORM\Column(name="invoice", type="integer", nullable=true) 
    */ 
    private $invoice; 

    //Rest of the entity... 

は、私はその後、OrderOneToMany関係にcascade={"persist"}オプションを追加しました::

/** 
* Orders 
* 
* @ORM\Entity 
*/ 
class Order 
{ 
    /** 
    * @ORM\OneToMany(targetEntity="Relation", mappedBy="order", cascade={"persist"}) 
    */ 
    protected $relation; 

    //Rest of the entity... 

のEtほら

は、ここに私のRelationsエンティティです!

1

リレーションシップレコードを保持してフラッシュする前に、オリジナルを保持してフラッシュする必要があります。あなたはエラーの理由で100%正しいです。

私は、ダイヤグラムから、あなたが追加して注文していることと同時に連絡先との関係を想定していますか?そうであれば、関係を維持してフラッシュする前に注文を維持してフラッシュする必要があります。また、主キーを関係テーブルに追加することもできます。

+0

あなたは正しいです、私は同時に注文と連絡先の関係を追加しようとしています。私は前に注文を洗い流そうとしましたが、次に 'カスケード= {" persist "}"の必要性についてエラーを受け取り、それを元に戻すと最初に関係を保存しようとします。あなたはどこかの実例を持っていますか?私は1つを見つけることができません... – cheesemacfly

+0

あなたは手動で関係を維持する必要があります。すべての 'cascade = {" persist "}'は、そのセットとの関係を持つエンティティを永続化すると自動的に '$ em-> persist($ relationshipObject)'を追加します。オフにし、手動で関係オブジェクトを永続化し、2回目のフラッシュを実行します。 –

+0

しかし、 'cascade = {" persist "}'を削除して、orderオブジェクトを最初に永続/フラッシュすると、 'TEST \ MyBundle \ Entity \ Orders#relations 'という関係で新しいエンティティが見つかりました。エンティティ:TEST \ MyBundle \ Entity \ Relations ... 'の永続操作をカスケードするように構成されていなかったものです。リレーションオブジェクトに 'detach()'を使用しようとしましたが、成功しませんでした... – cheesemacfly

3

この問題は、1)複合キーを持つ結合テーブル、2)フォームコンポーネント、3)結合テーブルがフォームコンポーネントの 'コレクション'フィールドによって作成されているエンティティである場合には一意ではないようです。私は多くの人が問題を抱えていたが、解決策はそれほど多くなかったので、私は私のことを分かち合うと思った。

2つの外部キーのインスタンスが1つだけデータベースに残るようにしたいので、私は複合プライマリキーを保持したかったのです。私はOrderItemのコレクションフィールドを持っていた形でOrderオブジェクトを構築した場合の例

/** @Entity */ 
class Order 
{ 
    /** @OneToMany(targetEntity="OrderItem", mappedBy="order") */ 
    private $items; 

    public function __construct(Customer $customer) 
    { 
     $this->items = new Doctrine\Common\Collections\ArrayCollection(); 
    } 
} 

/** @Entity */ 
class Product 
{ 
    /** @OneToMany(targetEntity="OrderItem", mappedBy="product") */ 
    private $orders; 
    ..... 

    public function __construct(Customer $customer) 
    { 
     $this->orders = new Doctrine\Common\Collections\ArrayCollection(); 
    } 
} 

/** @Entity */ 
class OrderItem 
{ 
    /** @Id @ManyToOne(targetEntity="Order") */ 
    private $order; 

    /** @Id @ManyToOne(targetEntity="Product") */ 
    private $product; 

    /** @Column(type="integer") */ 
    private $amount = 1; 
} 

として、私が直面した問題を this entity setupを使用して、私はせずに、エンティティをOrderItemに保存することができないであろうDoctrine EntityManagerは、OrderItem属性を持つOrderオブジェクトを保存することができませんでした(それは、それらをまとめて保存することを主張しているためです) 。カスケードをオフにすることはできません。関連するエンティティを保存していないと不平を言います。Orderを保存する前に、関連するエンティティを保存することはできません。どのような謎。 私の解決策は、関連付けられたエンティティを削除し、Orderを保存してから、関連付けられたエンティティをOrderオブジェクトに再導入して、再度を保存することでした。だから、最初の私は、ArrayCollectionの属性$items

class Order 
{ 
    ..... 
    public function setItemsArray(Doctrine\Common\Collections\ArrayCollection $itemsArray = null){ 
    if(null){ 
     $this->items->clear(); 
    }else{ 
     $this->items = $itemsArray; 
    } 
    .... 
} 

の質量割り当て機能を作成し、その後、私のコントローラで私が注文するためのフォームを処理する場所。

//get entity manager 
$em = $this->getDoctrine()->getManager(); 
//get order information (with items) 
$order = $form->getData(); 
//pull out items array from order 
$items = $order->getItems(); 
//clear the items from the order 
$order->setItemsArray(null); 
//persist and flush the Order object 
$em->persist($order); 
$em->flush(); 

//reintroduce the order items to the order object 
$order->setItemsArray($items); 
//persist and flush the Order object again): 
$em->persist($order); 
$em->flush(); 

それはあなたが(もっとここPersist object with two foreign identities in doctrineを参照)を2回を持続し、フラッシュする必要があることを吸います。しかし、それはあなたのための教えであり、力のすべてがあれば、あなたを束縛することができます。しかし、うまくいけば、オブジェクトはすでにデータベースに入っているので、編集ではなく新しいオブジェクトを作成するときにのみ、これを行う必要があります。