关于symfony(doctrine)中实体关系的咨询

Consulting about relationship of entities in symfony(doctrine)

我会具体一点。 我有实体任务、城市和组织者。 当我尝试删除管理器时,出现与任务有关的错误

An exception occurred while executing 'DELETE FROM Organizer WHERE id = ?' with params [522]:

SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (test.Quest, CONSTRAINT FK_82D6D713876C4DDA FOREIGN KEY (organizer_id) REFERENCES Organizer (id))

我对配置关系的正确方法感到非常困惑。 逻辑是:

  1. 我们添加了新城市。
  2. 我们添加了新的组织者并将城市放入组织者。
  3. 我们创建新的任务,然后将城市和组织者放入其中。
  4. 如果我们删除组织者 - 任务中的组织者 ID 必须是 移除(任务不得移除)。
  5. 如果我们删除组织者 - 并且必须删除城市中的组织者 ID 也是(并且不能删除城市)。

很抱歉我的描述很愚蠢,但我试图排除误解。

嗯,对于我的情况,我应该使用什么正确的实体关系?

class Quest {
     ...
     /**
     * @ORM\JoinColumn(name="organizer_id", referencedColumnName="id")
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Organizer")
     */
     protected $organizer;    
}

class Organizer {
    ...
    /**
     * @ORM\Column(type="string", length=140)
     */
    protected $name;

    /**
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\City", inversedBy="organizers")
     * @ORM\JoinTable(name="organizers_cities")
     */
    protected $cities;

    public function __construct() {
        $this->quests = new ArrayCollection(); // i don't remember why this is here
    }
}

class City {

        /**
         * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Organizer", mappedBy="cities")
         */
        protected $organizers;
        /**
         * Constructor
         */
        public function __construct() {
            $this->quests =  new \Doctrine\Common\Collections\ArrayCollection();
            $this->organizers =  new \Doctrine\Common\Collections\ArrayCollection();
        }
    }

问题很简单,您无法删除组织者,因为它已被现有任务引用。在您的情况下,您必须首先删除关系。我不知道用 doctrine 自动执行此操作的方法,但您可以在 preRemove 事件中配置一个事件侦听器,并将 Quest organizer 字段设置为 null。我不确定 symfony 2.1 中是否实现了事件侦听器,但我希望如此。您还可以选择在 remove 调用之前直接在控制器中执行 null 关系。同样的情况也适用于城市。检查此文档链接:

How to Register Event Listeners and Subscribers

Doctrine Lifecycle Events

希望对您有所帮助。

您必须配置 Doctrine 或您的数据库以将关系设置为空。

  • 有了学说,只需删除您的实体即可:

    $em=$this->getDoctrine()->getEntityManager(); // or getManager() in current Doctrine versions.
    $em->remove($organizer);
    $em->flush();
    
  • 与您的数据库:

    更改您的 JoinColumn 注释:

    class Quest {
         ...
         /**
         * @ORM\JoinColumn(nullable=false, onDelete="SET NULL",name="organizer_id", referencedColumnName="id")
         * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Organizer")
         */
         protected $organizer;    
    }
    

    通过第二种方法,您将能够使用 DQL 查询。 此方法绕道主义,首选第一种

我忘记了两件重要的事情。

  1. 学说生命周期事件
  2. php bin/console doctrine:generate:entities AppBundle/Entity/Quest 将只生成常用方法。 (有 没有 removeOrganizer() 函数 )

所以,解决方案很简单,但是......见下文。

class Quest {
    ...
    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Organizer", inversedBy="quests")
     * @ORM\JoinColumn(name="organizer_id", referencedColumnName="id")
     */
    protected $organizer;

   ...
  public function removeOrganizer()
    {
        $this->organizer = null;
        return $this;
    }
    public function removeCity()
    {
        $this->city = null;
        return $this;
    }
}
class Organizer {
    ...
    /**
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\City", inversedBy="organizers")
     */
    protected $cities;
    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Quest", mappedBy="organizer"))
     */
    protected $quests;

    public function __construct() {
        $this->quests = new ArrayCollection();
    }
     ...
    /**
     * @ORM\PreRemove()
     */
    public function removeRelationWithQuests() {
       foreach($this->getQuests() as $quest) {
            $quest->removeOrganizer()
                  ->setStatus(0);
       }
    }
}
class City {
     ...
    /**
     * @OneToMany(targetEntity="AppBundle\Entity\Quest", mappedBy="city"))
     */
    protected $quests;
    /**
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Organizer", mappedBy="cities")
     */
    protected $organizers;
    ...
   /**
     * @ORM\PreRemove()
     */
    public function removeRelationWithQuests() {
        foreach($this->getQuests() as $quest) {
            $quest->removeCity()
                  ->setStatus(0);
        }
    }
}

如您所见,我为任务实体添加了新函数 removeOrganizer 和 removeCity,并将其与 City 和 Organizer 实体中的事件 preRemove 一起使用。

PS 我相信有更好的实践来解决这样的任务。所以,我愿意为你接受批评。