Doctrine复合主键单向一对一关联保存时project_id被覆盖为null问题
这是映射配置错误,不属于Doctrine的bug。
问题原因
你的Passenger实体中project_id字段被同时映射到了两个属性:
- 作为复合主键的一部分,映射到
$projectId属性,你可以通过setProjectId手动赋值 - 作为和
Ticket关联的外键的一部分,映射到$ticket属性的关联配置
当你没有给$ticket赋值时,Doctrine的关联处理逻辑会自动将关联对应的外键字段project_id设为null,直接覆盖了你之前手动设置的projectId值,最终生成的SQL就会出现project_id为null的情况,触发非空约束报错。
而你设置了$ticket关联对象时,Doctrine会自动从Ticket对象中读取projectId的值填充到project_id外键字段,刚好满足非空要求,所以不会报错。
修复方案
修改Passenger实体中关联部分的注解,给对应project_id的JoinColumn增加insertable: false和updatable: false配置,禁止Doctrine通过关联逻辑操作这个字段,字段值完全由实体本身的$projectId属性控制:
#[OneToOne(targetEntity: "Ticket", cascade: ["persist"])] #[JoinColumn(name: "ticket_id", referencedColumnName: "id", nullable: true)] #[JoinColumn(name: "project_id", referencedColumnName: "project_id", insertable: false, updatable: false)] private ?Ticket $ticket;
如果你的业务逻辑要求Passenger的project_id必须和关联Ticket的project_id保持一致,可以在setTicket方法中补充同步逻辑:
public function setTicket(?Ticket $ticket): void { $this->ticket = $ticket; if ($ticket !== null) { $this->setProjectId($ticket->getProjectId()); } }
内容的提问来源于stack exchange,提问作者Volodymyr Kyrychenko
相关产品推荐
相关产品推荐

