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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 11:30:23