【问题标题】:One-To-Many relationship deletes foreign key in Doctrine一对多关系删除Doctrine中的外键
【发布时间】:2026-01-20 03:20:04
【问题描述】:

这快把我逼疯了。

一个Client 可以有多个Vehicles。

这是一对多的关系。尝试保存实体时,我收到一条错误消息,指出外键为空。当我删除 Doctrine 关系并单独存储 Vehicle 时,一切正常。

这就是我创建关系的方式:

class Vehicle {

    ...

    /**
     * @ORM\ManyToOne(targetEntity="Client", inversedBy="vehicles")
     * @ORM\JoinColumn(name="client_id", referencedColumnName="id")
     */
    public $client;

}

class Client {

    ...

    public function __construct()
    {
        parent::__construct();
        $this->vehicles = new \Doctrine\Common\Collections\ArrayCollection();
    }


    /**
     * @ORM\OneToMany(targetEntity="Vehicle", mappedBy="client", cascade={"persist"})
     */
    private $vehicles;

}

我尝试像这样保存实体:

$client = new Client();
$vehicle = new Vehicle();
$client->getVehicles()->add($vehicle);
$em->persist($client);
$em->flush();

接下来我得到一个 PDO 异常,指出 client_id 不能是 Vehicle 表上的 null

Doctrine 似乎没有正确复制外键。

我做错了什么?

【问题讨论】:

  • 你有没有persist()$vehicle在某个地方?
  • @andy 不,因为我在做cascade={"persist"}
  • 啊,对。详细检查代码:public $client 至少可能会导致旧版本 Doctrine 的代理出现问题。
  • @andy 好的,让我明天回到办公室试试
  • @andy 所有实例变量都不是private(当然应该是),但不幸的是,这并没有解决问题

标签: php database pdo doctrine-orm doctrine


【解决方案1】:

根据their docs

不能使用指向非主键的连接列。

Doctrine 会认为这些是主键并使用数据创建延迟加载代理,这可能会导致意外结果。出于性能原因,Doctrine 不能在运行时验证此设置的正确性,而只能通过 Validate Schema 命令。

显然您需要一种不同的方法。

他们的例子中给出了解决方案:

CREATE TABLE product (
    id INTEGER,
    name VARCHAR,
    PRIMARY KEY(id)
);
CREATE TABLE product_attributes (
    product_id INTEGER,
    attribute_name VARCHAR,
    attribute_value VARCHAR,
    PRIMARY KEY (product_id, attribute_name)
);

此架构应按如下方式映射到产品实体:

class Product
{
    private $id;
    private $name;
    private $attributes = array();
}

attribute_name 列包含键,attribute_value 包含$attributes 中每个数组元素的值。

【讨论】: