所以,我现在已经玩了一段时间使用学说并在一些基础项目中使用它,但我决定回过头来深入研究它能做些什么。
我现在决定转而使用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;
}
}
答案 0 :(得分:1)
你的基本想法是正确的。如果你想拥有一个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: Best way to handle many-to-many with extra columns in reference table
答案 1 :(得分:0)
如果我正确理解了这个模型,配方的构造及其相关的recipeIngredients是并发的。如果调用了receipeIngredient-&gt; setRecipe(),则在持久化且没有id之前,您可能没有id,默认null将放在recipeIngredient-&gt; 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()));
}
答案 2 :(得分:0)
我不确定这是否是一个解决方案,但它很容易尝试,可能会有所帮助。 当我创建这种关系时,我会用另一个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;
// ...
名称表示关系表中字段的名称,而 referencedColumnName 是引用实体表中的id字段的名称(即b_id是列中的a_rel_b引用表B)中的列id
答案 3 :(得分:0)
你不能,因为它不再是一种关系[这是def,是两个原始实体集合的笛卡尔积的一个子集]。
您需要一个中间实体,同时引用Recipe
和Ingredient
- 称之为RecipeElement
,RecipeEntry
左右,并添加您想要的字段。
您可以向Recipe
添加地图,在其中保存您保存的每个Ingredient
的属性,如果没有重复项,则易于维护。