Symfony2 ManyToMany 关系也保存存在的相关实体

Symfony2 ManyToMany relation save also the existent related entity

我在 Symfony2.8 上遇到了 Doctrine ManyToMany 实体关系的问题。 我有实体 Trip,它可以由许多 Experience 实体组成。

这是我的旅行定义:

namespace MyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Trip
 *
 * @ORM\Table(name="trip")
 * @ORM\Entity(repositoryClass="MyBundle\Repository\TripRepository")
 * @ORM\HasLifecycleCallbacks
 */
class Trip
{
    use ORMBehaviors\Timestampable\Timestampable;
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;    

    // other fields

    /**
     * @ORM\ManyToMany(targetEntity="MyBundle\Entity\Experience", inversedBy="trips")
     * @ORM\JoinTable(name="experience_trip",
     *  joinColumns={
     *     @ORM\JoinColumn(name="trip_id", referencedColumnName="id")
     *  },
     *  inverseJoinColumns={
     *     @ORM\JoinColumn(name="experience_id", referencedColumnName="id")
     *  }
     * )
     */
    private $experiences;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->experiences = new \Doctrine\Common\Collections\ArrayCollection();
    }

    // other setters and getters

    /**
     * Add experience
     *
     * @param \MyBundle\Entity\Experience $experience
     *
     * @return Trip
     */
    public function addExperience(\MyBundle\Entity\Experience $experience)
    {
        $this->experiences[] = $experience;

        return $this;
    }

    /**
     * Remove experience
     *
     * @param \MyBundle\Entity\Experience $experience
     */
    public function removeExperience(\MyBundle\Entity\Experience $experience)
    {
        $this->experiences->removeElement($experience);
    }

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

}

在另一边我有体验实体:

namespace MyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Experience
 *
 * @ORM\Table(name="experience")
 * @ORM\Entity(repositoryClass="MyBundle\Repository\ExperienceRepository")
 */
class Experience
{

    use ORMBehaviors\Translatable\Translatable;
    use ORMBehaviors\Timestampable\Timestampable;


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

    /**
     * @ORM\ManyToMany(targetEntity="MyBundle\Entity\Trip", mappedBy="experiences")
     */
    private $trips;

    // other fields

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->trips = new \Doctrine\Common\Collections\ArrayCollection();
    }

    // other setters and getters

    /**
     * Add trip
     *
     * @param \MyBundle\Entity\Trip $trip
     *
     * @return Experience
     */
    public function addTrip(\MyBundle\Entity\Trip $trip)
    {
        $this->trips[] = $trip;

        return $this;
    }

    /**
     * Remove trip
     *
     * @param \MyBundle\Entity\Trip $trip
     */
    public function removeTrip(\MyBundle\Entity\Trip $trip)
    {
        $this->trips->removeElement($trip);
    }

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

在controller中,用户可以生成一个新的Trip,将对象放到session中调用,直到真正关联起来。

/**
 * @Route("/add-experience", name="add_experience")
 */
public function addExperienceAction(Request $request)
{
    $experienceId = $request->query->get('experience');
    $em = $this->getDoctrine()->getManager();

    $experience = $em->getRepository('MyBundle:Experience')->find($experienceId);
    if (!$experience || !get_class($experience) == 'MyBundle:Experience') {
        $response = array("message" => "Experience not found", "success" => false);

        return new Response(json_encode($response));
    }

    $session = $request->getSession();
    $trip = $session->get('trip');
    // This service only construct parameters
    $searchParameters = $this->get('mybundle.search')->buildSearchParameters();
    if (!$trip) {
        $trip = new Trip();
        $trip->setStartDate($searchParameters['startDate']);
        $trip->setEndDate($searchParameters['endDate']);
    }

    $trip->addExperience($experience);
    $trip->setClient($this->getUser()); /** user can be null */
    $em->persist($trip);
    $em->flush();

    $session->set('trip', $trip);

    $response = array("message" => "Experience n.$experienceId added correctly", "success" => true);

    return new Response(json_encode($response));
}

问题。 第一次调用时,它就像一个魅力,添加 experience_trip 条目,一切正常。 在第二次调用时,具有不同的经验,坚持旅行正在寻找经验实体的级联,抛出错误:

A new entity was found through the relationship 'MyBundle\Entity\Trip#experiences' that was not configured to cascade persist operations for entity: . To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}).

这是因为尝试添加一个新的体验实体,事实上,使用 cascade={"persist"},由于字段的唯一性,在体验重复时生成 sql 异常。

同一模型由 Sonata TripAdmin class 正确管理,而不是尝试在旅行持续中添加新体验,而不是避免创建 ExperienceTrip 实体。在 experience_trip table 中我可以正确地看到正确的关联。

为什么保存行程,第二次尝试插入新体验?

提前致谢,对不起我的英语。

我自己找到了解决方案,也感谢

由于某种原因,会话中的实体已分离并且不是有效实体。所以坚持再尝试添加。