7

それで、私はしばらくDoctrineを使って遊んでいて、いくつかの基本的なプロジェクトでそれを持っていますが、戻って何ができるかを詳しく調べることにしました.

私は現在、選択したフレームワークとして symfony 2 に切り替えることを決定し、doctrine 2 で何ができるかをより深く調べています。

私が理解しようとしてきたことの 1 つは、ドクトリン内の多対多の関係です。私はレシピシステムの構築を開始しており、レシピと材料の関係に取り組んでおり、レシピ、レシピ材料、材料の 3 つのエンティティが得られました。直接の多対多の関係を使用できない理由は、各成分の結合テーブル (単位と数量) に 2 つの追加の列を格納したいからです。

現時点で私が抱えている問題は、エンティティが正常に存続することですが、結合テーブルのレシピ ID が挿入されないことです。私は考えることができるすべてを試し、答えを探してすべてのスレッドとウェブサイトを調べました. 私が見逃しているのは完全に明白なものだと確信しています。助けてください、以下は私がこれまでに持っているコードです:

<?php
namespace Recipe\RecipeBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
 * @ORM\Entity
 * @ORM\Table(name="recipe")
 * @ORM\HasLifecycleCallbacks()
 */
class Recipe{

/**
 * @ORM\Id
 * @ORM\Column(type="integer")
 * @ORM\GeneratedValue(strategy="AUTO")
 */
protected $id;

/**
 * @ORM\OneToMany(targetEntity="RecipeIngredient", mappedBy="recipe", cascade=       {"persist"})
 */
protected $ingredients;
/**
 * @ORM\Column(type="string")
 * @var string $title
 *
 */
protected $title;
/**
 * Constructor
 */
public function __construct()
{
    $this->ingredients = new \Doctrine\Common\Collections\ArrayCollection();
}

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

/**
 * Add ingredients
 *
 * @param \Recipe\RecipeBundle\Entity\RecipeIngredient $ingredients
 * @return Recipe
 */
public function addIngredient(\Recipe\RecipeBundle\Entity\RecipeIngredient $ingredients)
{
    $ingredients->setRecipe($this);
    $this->ingredients[] = $ingredients;

    return $this;
}

/**
 * Remove ingredients
 *
 * @param \Recipe\RecipeBundle\Entity\RecipeIngredient $ingredients
 */
public function removeIngredient(\Recipe\RecipeBundle\Entity\RecipeIngredient $ingredients)
{
    $this->ingredients->removeElement($ingredients);
}

/**
 * Get ingredients
 *
 * @return \Doctrine\Common\Collections\Collection
 */
public function getIngredients()
{
    return $this->ingredients;
}

/**
 * Set title
 *
 * @param string $title
 * @return Recipe
 */
public function setTitle($title)
{
    $this->title = $title;

    return $this;
}

/**
 * Get title
 *
 * @return string
 */
public function getTitle()
{
    return $this->title;
}
}

とレシピ食材

/**
 * @ORM\Id
 * @ORM\Column(type="integer")
 * @ORM\GeneratedValue(strategy="AUTO")
 */
protected $id;

/**
 * @ORM\ManyToOne(targetEntity="Recipe", inversedBy="ingredients")
 * */
protected $recipe;

/**
 * @ORM\ManyToOne(targetEntity="Ingredient", inversedBy="ingredients" , cascade={"persist"})
 * */
protected $ingredient;

/**
 * @ORM\Column(type="string")
 * @var string  $quantity
 *
 */
protected $quantity;

/**
 * @ORM\Column(type="string")
 * @var string $unit
 *
 */
protected $unit;

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

/**
 * Set quantity
 *
 * @param string $quantity
 * @return RecipeIngredient
 */
public function setQuantity($quantity)
{
    $this->quantity = $quantity;

    return $this;
}

/**
 * Get quantity
 *
 * @return string
 */
public function getQuantity()
{
    return $this->quantity;
}

/**
 * Set unit
 *
 * @param string $unit
 * @return RecipeIngredient
 */
public function setUnit($unit)
{
    $this->unit = $unit;

    return $this;
}

/**
 * Get unit
 *
 * @return string
 */
public function getUnit()
{
    return $this->unit;
}

/**
 * Set recipe
 *
 * @param \Recipe\RecipeBundle\Entity\Recipe $recipe
 * @return RecipeIngredient
 */
public function setRecipe(\Recipe\RecipeBundle\Entity\Recipe $recipe = null)
{
    $this->recipe = $recipe;

    return $this;
}

/**
 * Get recipe
 *
 * @return \Recipe\RecipeBundle\Entity\Recipe
 */
public function getRecipe()
{
    return $this->recipe;
}

/**
 * Set ingredient
 *
 * @param \Recipe\RecipeBundle\Entity\Ingredient $ingredient
 * @return RecipeIngredient
 */
public function setIngredient(\Recipe\RecipeBundle\Entity\Ingredient $ingredient = null)
{
    $this->ingredient = $ingredient;

    return $this;
}

/**
 * Get ingredient
 *
 * @return \Recipe\RecipeBundle\Entity\Ingredient
 */
public function getIngredient()
{
    return $this->ingredient;
}
}
4

4 に答える 4

1

あなたの基本的な考えは正しいものです。ManyToMany 関係を持ちたいが、結合テーブルに追加のフィールドを追加する必要がある場合、方法はまさに説明したとおりです: 2 つの ManyToOne 関係といくつかの追加フィールドを持つ新しいエンティティを使用します。

残念ながら、あなたの問題はそこにある可能性が高いため、コントローラーコードを提供していません。

基本的に、次のようなことをすると:

$ri = new RecipeIngredient;
$ri->setIngredient($i);
$ri->setRecipe($r);
$ri->setQuantity(1);
$em->persist($ri);
$em->flush();

データベース テーブルには、recipe_id と materials_id の両方が正しく入力された正しいレコードが常に取得されます。

コードをチェックアウトすると、次の方法も機能するはずですが、個人的には、これは間違いに敏感だと思います。

$ri = new RecipeIngredient;
$ri->setIngredient($i);
$ri->setQuantity(1);
// here we assume that Recipe->addIngredient also does the setRecipe() for us and 
// that the cascade field is set correctly to cascade the persist on $ri
$r->addIngredient($ri);
$em->flush();

さらに読むために、このテーマに関する他のトピックをお勧めします。

于 2015-04-17T12:53:30.810 に答える
0

このモデルを正しく理解していれば、レシピとそれに関連するレシピの構成要素は並行して作成されます。receipeIngredient->setRecipe() が呼び出された場合、ID がないと永続化するまで ID がない可能性があります。デフォルトの null は、recipeIngredient->recipe フィールドに配置されます。これはしばしば cascade: "persist" で処理されます (あなたの例ではレシピフィールドには存在しませんが、コントローラーで明示的に処理できます:

/** 
  * Creates a new Recipe entity.
  *
  */
public function createAction(Request $request)
{
  $em = $this->getDoctrine()->getManager();
  $form = $this->createForm(new RecipeType());  
  $form->bind($request);

  if ($form->isValid()){
    $data = $form->getData();
    $recipeId = $data->getId();
    $recipeIngredients=$data->getIngredients();
    $recipe=$em->getRepository('reciperecipeBundle:Recipe')
               ->findOneById($RecipeId);
    if (null === $Recipe)
      {$Recipe=new Recipe();}  
    foreach ($recipeIngredients->toArray() as $k => $i){
      $recipeIngredient=$em->getRepository('reciperecipeBundle:recipeIngredient')
                           ->findOneById($i->getId());
      if (null === $recipeIngredient)
        {$recipeIngrediente=new RecipeIngredient();}  
      $recipe->addIngredient($i);

      // Next line *might* be handled by cascade: "persist"        
      $em->persist($recipeIngredient);
    }  
    $em->persist($Recipe);
    $em->flush();
    return $this->redirect($this->generateUrl('Recipe', array()));
  }   

  return $this->render('reciperecipeBundle:Recipe:new.html.twig'
                      ,array('form'   => $form->createView()));  
}
于 2012-11-22T16:14:05.093 に答える
0

これが解決策になるかどうかはよくわかりませんが、試してみるのは簡単で、おそらく役立つでしょう。この種のリレーションシップを作成するときは、 次の例のように@ORM\JoinColumnという別の注釈を記述します。

エンティティA、エンティティB、および関係を表すクラスABがあり、あなたの場合のように他のフィールドを追加します。

私の関係は次のようになります。

use Doctrine\ORM\Mapping as ORM;

/**
 *  
 *
 * @ORM\Table(name="a_rel_b")
 * @ORM\Entity
 */
class AB
{

    /**
     * @var integer
     *  @ORM\Id
     * @ORM\ManyToOne(targetEntity="A", inversedBy="b")
     * @ORM\JoinColumn(name="a_id", referencedColumnName="id")  
     **/

    private $a;


    /**
     * @var integer
     *  @ORM\Id
     * @ORM\ManyToOne(targetEntity="B", inversedBy="a")
     * @ORM\JoinColumn(name="b_id", referencedColumnName="id")
     **/
    private $b;
// ...

nameは関係テーブルのフィールドの名前を意味し、referencedColumnNameは参照されるエンティティ テーブルの id フィールドの名前です (つまり、 b_id はテーブル B の列 id を参照する a_rel_b の列です)。

于 2013-10-22T11:13:11.433 に答える
0

それはもはや関係ではないため、できません[これは、定義により、2つの元のエンティティのセットのデカルト積のサブセットです]。

Recipe両方への参照を含む中間エンティティが必要ですIngredient- それを呼び出すかRecipeElementRecipeEntry必要なフィールドを追加します。

Recipeいずれかの方法で、保存するそれぞれの属性を保存するマップを に追加できますIngredient。重複がない場合は簡単に維持できます。

さらに読むには、このよくある質問をご覧ください。

于 2013-10-22T11:22:49.257 に答える