使用doctrine上的额外字段创建双向多对多关联

时间:2016-09-07 22:16:34

标签: database doctrine-orm many-to-many symfony

我使用symfony 3和doctrine,这是我的问题:
我想创造由不同数量的成分组成的菜肴。

数据库将如下所示:

[ Dish ] <===> [ IngredientDish ] <===> [ Ingredient ]
[------]       [----------------]       [------------]
[- name]       [- Dish          ]       [-name       ]
[      ]       [- Ingredient    ]       [            ]
[      ]       [- quantity      ]       [            ]
[------]       [----------------]       [------------]

这是我的代码:

Dish.php

/**
 * @ORM\Table(name="dish")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\DishRepository")
 */
class Dish
{

     /**
      * @ORM\OneToMany(targetEntity="AppBundle\Entity\IngredientDish",
      *         mappedBy="dish")
      */
     private $ingredientsDish;

     [...]

     public function addIngredientDish(IngredientDish $ingredient)
     {
         $this->ingredientsDish[] = $ingredient;

         return $this;
     }

     public function getIngredientsDish()
     {
         return $this->ingredientsDish;
     }

 }

为ingredient.php

/**
 * @ORM\Table(name="ingredient")
 *    @ORM\Entity(repositoryClass="AppBundle\Repository\IngredientRepository")
 */
 class Ingredient
 {

     /**
      * @ORM\OneToMany(targetEntity="AppBundle\Entity\IngredientDish",
      *     mappedBy="ingredient")
      * @Assert\Type(type="AppBundle\Entity\IngredientDish")
      */
     private $ingredientsDish;

     [...]

     public function addIngredientDish(IngredientDish $ingredientDish)
     {
         $this->ingredientDish[] = $ingredientDish;

         return $this;
      }

     public function getingredientsDish()
     {
         return $this->ingredients;
     }

 }

IngredientDish.php

/**
 * @ORM\Table(name="ingredient_dish")
 *    @ORM\Entity(repositoryClass="AppBundle\Repository\IngredientDishRepository")
 */
class IngredientDish
{

    /**
     * @ORM\Column(name="quantity", type="smallint")
     * @Assert\NotBlank()
     * @Assert\Length(min=1)
     */
    private $quantity = 1;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Ingredient",
     *      inversedBy="ingredientsDish")
     * @Assert\Type(type="AppBundle\Entity\Ingredient")
     */
    private $ingredient;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Dish",
     *      inversedBy="ingredientsDish")
     * @ORM\JoinColumn()
     * @Assert\Type(type="AppBundle\Entity\Dish")
     */
    private $dish;

    public function __construct(Ingredient $ingredient, Dish $dish, $quantity = 1)
    {
        $this->setIngredient($ingredient);
        $this->setDish($dish);
        $this->setQuantity($quantity);
    }

    public function setQuantity($quantity)
    {
        $this->quantity = $quantity;

        return $this;
    }

    public function getQuantity()
    {
        return $this->quantity;
    }

    public function setIngredient(Ingredient $ingredient)
    {
        $this->ingredient = $ingredient;
        return $this;
    }

    public function getIngredient()
    {  
        return $this->ingredient;
    }

    public function setDish(Dish $dish)
    {
        $this->dish = $dish;
        return $this;
    }

    public function getDish()
    {
        return $this->dish;
    }

}

我的测试代码

$em = $this->getDoctrine()->getManager();

//Get an apple pie
$dish = $em->getRepository('AppBundle:Dish')->find(6);

//Get an apple
$ingredient = $em->getRepository('AppBundle:Ingredient')->find(11);

$quantityApple = 5;

$ingredientDish = new IngredientDish($ingredient, $dish, $quantityApple);

$ingredient->addIngredientDish($ingredientDish);

$dish->addIngredientDish($ingredientDish);

$em->persist($ingredientDish);
$em->persist($dish);
$em->flush();

执行后,我有一个有趣的条目:

mysql> select * from ingredient_dish;
+----+---------------+----------+---------+
| id | ingredient_id | quantity | dish_id |
+----+---------------+----------+---------+
| 1  |            11 |        5 |       6 |
+----+---------------+----------+---------+

但之后,如果我试着拿到我的菜:

$dish = $em->getRepository('AppBundle:Dish')->find(6);
dump($dish->getIngredientsDish());

它没有成分:

PersistentCollection {#1180 ▼
    -snapshot: []
    -owner: Dish {#1146 ▶}
    -association: array:15 [ …15]
    -em: EntityManager {#1075 …11}
    -backRefFieldName: "dish"
    -typeClass: ClassMetadata {#1157 …}
    -isDirty: false
    #collection: ArrayCollection {#1181 ▼
        -elements: [] <<<<<<<<<<<<<<<<<<<<< EMPTY
    }
    #initialized: false
}

执行我的测试代码后数据库不为空,所以我认为有一个getter错误。 你能帮帮我吗,你看错了什么吗?

感谢您的帮助! :)

2 个答案:

答案 0 :(得分:1)

我认为一切都很好,但你的懒惰加载误导了你,这显然比你想象的要聪明。 ; - )

当你这样做时

$dish->getIngredientsDish();

您收到的PersistentCollection扩展了AbstractLazyCollection

但仍未从DB(!)

中提取该集合

仔细查看var_dump结果

PersistentCollection {#1180 ▼
    -snapshot: []
    -owner: Dish {#1146 ▶}
    -association: array:15 [ …15]
    -em: EntityManager {#1075 …11}
    -backRefFieldName: "dish"
    -typeClass: ClassMetadata {#1157 …}
    -isDirty: false
    #collection: ArrayCollection {#1181 ▼
        -elements: [] <<<<<<<<<<<<<<<<<<<<< EMPTY //<= yeah empty, but...
    }
    #initialized: false // <= it's still not initialized!
}

正如您所看到的那样initialized属性表明该集合仍未初始化(未从数据库中获取)。

试着用它。它将在首次使用时获取该集合。

答案 1 :(得分:0)

首先,注释映射存在一些问题。 进行以下更改:

/**
 * @ORM\Table(name="dish")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\DishRepository")
 */
class Dish
{
    /**
     * @ORM\Column(name="dish_id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $dish_id;

    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\IngredientDish",
     *         mappedBy="dish")
     */
    private $ingredientsDish = null;

    public function __construct() {
         $this->ingredientsDish = new ArrayCollection();

    }
    ...
}
/**
 * @ORM\Table(name="ingredient_dish")
 *    @ORM\Entity(repositoryClass="AppBundle\Repository\IngredientDishRepository")
 */
class IngredientDish
{
    ...

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Dish",
     *      inversedBy="ingredientsDish")
     * @ORM\JoinColumn(name="dish_id", referencedColumnName="country_id")
     * @Assert\Type(type="AppBundle\Entity\Dish")
     */
    private $dish;
    ...
}

在Dish实体中,您需要有一个ArrayCollection的构造函数,并将其设置为null。

您还可以查看我的另一篇文章(在stackoverflow上参考:

Doctrine Entities Relations confusing