【问题标题】:Consulting about relationship of entities in symfony(doctrine)symfony(doctrine)中实体关系的咨询
【发布时间】:2016-12-05 01:43:15
【问题描述】:

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

执行 'DELETE FROM Organizer WHERE id 时发生异常 = ?'带参数 [522]:

SQLSTATE[23000]:违反完整性约束:1451 无法删除或 更新父行:外键约束失败(test.Quest, 约束 FK_82D6D713876C4DDA 外键 (organizer_id) 参考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-orm doctrine symfony symfony-2.1


    【解决方案1】:

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

    How to Register Event Listeners and Subscribers

    Doctrine Lifecycle Events

    希望对您有所帮助。

    【讨论】:

      【解决方案2】:

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

      • 使用学说,只需删除您的实体:

        $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 查询。 此方法绕过教义,首选第一种。

      【讨论】:

      • 他不想在级联上删除 Quest,只使关系为空,你确定这是你的代码在做什么吗?
      • 哦,好吧没明白。我重写了答案。谢谢。
      【解决方案3】:

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

      1. 教义生命周期事件
      2. php bin/控制台原则:生成:实体 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);
              }
          }
      }
      

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

      PS 我有信心解决这样的任务有更好的做法。所以,我愿意为你批评。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-02-27
        • 1970-01-01
        • 2013-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多