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
排查建议
- 同步实体集合与数据库状态:取消代码中
$player->getGameQuestLinks()->clear();的注释,删除关联对象后清理Player侧的集合,避免Doctrine认为关联仍需存在而重新插入。 - 检查隐式级联配置:排查
GameQuest或其他关联实体是否配置了级联持久化,导致删除后对象被重新关联并触发持久化。 - 监控UnitOfWork状态:在flush前后执行以下代码,确认是否有意外标记为待插入的实例:
// flush前 var_dump($this->em->getUnitOfWork()->getScheduledEntityInsertions()); $this->em->flush(); // flush后 var_dump($this->em->getUnitOfWork()->getScheduledEntityInsertions());
- 排查数据库触发器:检查MySQL表
player_retailer_game_quest_link是否存在INSERT触发器,导致删除后自动重建数据。 - 验证映射一致性:确认
PlayerRetailerGameQuestLink的player属性inversedBy与PlayerRetailer的gameQuestLinks属性mappedBy指向完全一致。 - 改用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
相关产品推荐
相关产品推荐

