You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Doctrine ORM无法从MySQL数据库删除实体的排查求助

问题:Doctrine删除PlayerGameQuestLink后条目自动重建

关联关系

  • Game <-> GameQuest[]
  • Player <-> PlayerGameQuestLink[]
    PlayerGameQuestLink 实体存储玩家任务的激活、完成等元数据,Player侧未配置级联操作。

关联映射代码

Player侧的OneToMany关联定义:

/**
 * @ORM\OneToMany(targetEntity="App\Entity\PlayerGameQuestLink", mappedBy="player")
 */
 private $gameQuestLinks;

PlayerRetailerGameQuestLink实体(不含getter/setter):

namespace App\Entity;
    
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="player_retailer_game_quest_link")
 */
class PlayerRetailerGameQuestLink
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private int $id;
    
    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\PlayerRetailer", inversedBy="gameQuestLinks")
     */
    private $player;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\GameQuest")
     */
    private $gameQuest;
    
    /**
     * @ORM\Column(type="datetime", nullable="true")
     */
    private $activatedAt = null;

    /**
     * @ORM\Column(type="datetime", nullable="true")
     */
    private $doneAt = null;
    
    /**
     * @ORM\Column(type="datetime", nullable="true")
     */
    private $completedAt = null;
}

异常的删除代码

执行无异常但删除失败的测试代码:

public function resetGameQuests(Game $game)
{
    $players = $game->getPlayers();
    /**
     * @var Player $player
     */
    foreach ($players as $player) {
        $player->getGameQuestLinks()->forAll(function($index, $link) {
            $this->em->remove($link);
        });
        //$player->getGameQuestLinks()->clear();
        //$this->em->persist($player);
    }
    $this->em->flush();

//   $gameQuests = $game->getGameQuests()->toArray();
//    foreach ($gameQuests as $gameQuest) {
//        $this->em->remove($gameQuest);
//    }
//    $game->getGameQuests()->clear();
//
//    $this->em->flush();

//    $this->createGameQuests($game);
}

调试现象

  • 系统生成并执行了正确的DELETE SQL语句
  • PDO commit()返回成功,但表中被删除的条目会以新ID自动重建
  • 手动执行相同的DELETE语句,删除操作正常生效

已尝试的操作

  • 手动开启事务执行删除,操作成功
  • 修改Doctrine配置,移除事务调用并开启自动提交,问题依旧
  • 断点排查未发现触发插入或集合更新的代码逻辑

环境信息

  • Doctrine 2.7.1
  • Symfony 5.3
  • MySQL 8.0.36
  • PHP 8.3.2
  • Windows 10 1909

排查建议

  1. 同步实体集合与数据库状态:取消代码中$player->getGameQuestLinks()->clear();的注释,删除关联对象后清理Player侧的集合,避免Doctrine认为关联仍需存在而重新插入。
  2. 检查隐式级联配置:排查GameQuest或其他关联实体是否配置了级联持久化,导致删除后对象被重新关联并触发持久化。
  3. 监控UnitOfWork状态:在flush前后执行以下代码,确认是否有意外标记为待插入的实例:
// flush前
var_dump($this->em->getUnitOfWork()->getScheduledEntityInsertions());
$this->em->flush();
// flush后
var_dump($this->em->getUnitOfWork()->getScheduledEntityInsertions());
  1. 排查数据库触发器:检查MySQL表player_retailer_game_quest_link是否存在INSERT触发器,导致删除后自动重建数据。
  2. 验证映射一致性:确认PlayerRetailerGameQuestLink的player属性inversedBy与PlayerRetailer的gameQuestLinks属性mappedBy指向完全一致。
  3. 改用DQL批量删除:绕过对象集合操作,直接执行批量删除DQL,避免Doctrine对象管理逻辑干扰:
$dql = 'DELETE FROM App\Entity\PlayerRetailerGameQuestLink l WHERE l.player IN (:players)';
$query = $this->em->createQuery($dql)->setParameter('players', $players);
$query->execute();

内容的提问来源于stack exchange,提问作者Alex654

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 05:17:04