Symfony 6.4使用EntityManagerInterface删除时误删两条记录问题
Symfony 6.4 复合主键实体误删多条记录的解决方法
问题核心原因
你的PROPOSITION表使用复合主键(TESTID,RUBRIQUEID,QUESTIONID,PROPOSITIONID),但实体类大概率未正确配置复合主键映射。Doctrine仅识别了PROPOSITIONID作为唯一主键,导致执行删除时生成的SQL是DELETE FROM PROPOSITION WHERE PROPOSITIONID = ?,从而误删所有PROPOSITIONID相同的记录。
解决步骤
1. 修正实体类的复合主键配置
必须让Doctrine识别所有4个字段作为复合主键,有两种常用配置方式:
方式一:使用@IdClass
先创建主键值对象类:
<?php namespace App\Entity; class PropositionId { public int $TESTID; public int $RUBRIQUEID; public int $QUESTIONID; public int $PROPOSITIONID; // Doctrine需要的相等性判断方法 public function equals(mixed $other): bool { if (!$other instanceof self) return false; return $this->TESTID === $other->TESTID && $this->RUBRIQUEID === $other->RUBRIQUEID && $this->QUESTIONID === $other->QUESTIONID && $this->PROPOSITIONID === $other->PROPOSITIONID; } public function hashCode(): int { return hash('sha256', sprintf('%d-%d-%d-%d', $this->TESTID, $this->RUBRIQUEID, $this->QUESTIONID, $this->PROPOSITIONID)); } }
然后修改Proposition实体类:
<?php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: PropositionRepository::class)] #[ORM\Table(name: 'PROPOSITION')] #[ORM\IdClass(PropositionId::class)] // 指定主键类 class Proposition { #[ORM\Id] #[ORM\Column(type: 'integer')] private int $TESTID; #[ORM\Id] #[ORM\Column(type: 'integer')] private int $RUBRIQUEID; #[ORM\Id] #[ORM\Column(type: 'integer')] private int $QUESTIONID; #[ORM\Id] #[ORM\Column(type: 'integer')] private int $PROPOSITIONID; // 其他字段及getter/setter方法... }
方式二:使用@EmbeddedId
创建可嵌入的主键类:
<?php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Embeddable] class PropositionId { #[ORM\Column(type: 'integer')] public int $TESTID; #[ORM\Column(type: 'integer')] public int $RUBRIQUEID; #[ORM\Column(type: 'integer')] public int $QUESTIONID; #[ORM\Column(type: 'integer')] public int $PROPOSITIONID; public function equals(mixed $other): bool { if (!$other instanceof self) return false; return $this->TESTID === $other->TESTID && $this->RUBRIQUEID === $other->RUBRIQUEID && $this->QUESTIONID === $other->QUESTIONID && $this->PROPOSITIONID === $other->PROPOSITIONID; } public function hashCode(): int { return hash('sha256', sprintf('%d-%d-%d-%d', $this->TESTID, $this->RUBRIQUEID, $this->QUESTIONID, $this->PROPOSITIONID)); } }
修改Proposition实体类:
<?php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: PropositionRepository::class)] #[ORM\Table(name: 'PROPOSITION')] class Proposition { #[ORM\Embedded(class: PropositionId::class)] private PropositionId $id; public function __construct() { $this->id = new PropositionId(); } // 主键字段的getter/setter示例 public function getTESTID(): int { return $this->id->TESTID; } public function setTESTID(int $TESTID): self { $this->id->TESTID = $TESTID; return $this; } // 同理添加RUBRIQUEID、QUESTIONID、PROPOSITIONID的getter/setter... }
2. 清理Doctrine元数据缓存
配置修改后,需要清空元数据缓存确保生效:
php bin/console doctrine:cache:clear-metadata
3. 验证删除逻辑
配置完成后,Doctrine会生成包含所有复合主键条件的删除SQL:
DELETE FROM PROPOSITION WHERE TESTID = ? AND RUBRIQUEID = ? AND QUESTIONID = ? AND PROPOSITIONID = ?
此时执行你的删除代码,只会删除目标单条记录。
调试建议
可以开启Doctrine SQL日志,查看实际执行的SQL语句:
在.env文件中修改数据库连接参数,添加logging=true:
DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=mariadb-10.6.7&logging=true"
然后查看日志确认删除条件是否正确。
内容的提问来源于stack exchange,提问作者Souyette
相关产品推荐
相关产品推荐

