[英]Doctrine 2 Many to Many relation with additional columns in join table
所以,我現在已經玩了一段時間使用學說並在一些基礎項目中使用它,但我決定回過頭來深入了解它能做些什么。
我現在決定切換到symfony 2作為我選擇的框架,並且正在研究更深入的教義2可以做什么。
我一直試圖解決的一件事是學說中的多對多關系。 我開始建立一個配方系統,正在研究配方和配料之間的關系,這給了我3個實體,配方,配方成分和成分。 我不能使用直接多對多關系的原因是因為我想在每個成分的連接表(單位和數量)中存儲兩個額外的列。
我目前遇到的問題是實體仍然存在,但是沒有插入連接表中的recipe_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;
}
}
和recipeIngredient
/**
* @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;
}
}
你的基本想法是正確的。 如果你想擁有一個ManyToMany關系,但你需要在連接表中添加額外的字段,那么完全按照你的描述:使用一個具有2個ManyToOne關系和一些附加字段的新實體。
很遺憾,您還沒有提供控制器代碼,因為很可能您的問題就在那里。
基本上如果你做的事情如下:
$ri = new RecipeIngredient;
$ri->setIngredient($i);
$ri->setRecipe($r);
$ri->setQuantity(1);
$em->persist($ri);
$em->flush();
您應始終在數據庫表中獲得正確的記錄,並正確填寫recipe_id和ingredient_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();
為了進一步閱讀,我建議關於這個主題的其他主題,例如: Doctrine2:在參考表中使用額外列處理多對多的最佳方法
如果我正確理解這個模型,配方的構造及其相關的recipeIngredients是並發的。 如果調用了receipeIngredient-> setRecipe(),那么在持久化並且沒有id之前,您可能沒有id,缺省的null將放在recipeIngredient-> recipe字段中。 這通常使用級聯處理:“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()));
}
我不確定這是否是一個解決方案,但它很容易嘗試,可能會有所幫助。 當我創建這種類型的關系時,我用來編寫另一個anotation,即@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是a_rel_b中引用表B中列id的列)
你不能,因為它不再是一種關系[這是def,兩個原始實體的集合的笛卡爾積的子集]。
你需要一個中間實體,引用Recipe
和Ingredient
- 稱之為RecipeElement
, RecipeEntry
或者左右,並添加你想要的字段。
您也可以在Recipe
添加地圖,在其中保存您保存的每種Ingredient
的屬性,如果沒有重復,則易於維護。
如需進一步閱讀,請查看這個熱門問題 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.