Doctrine实体双LAZY模式OneToMany关联取数异常问题
结论
Doctrine ORM原生支持同一实体配置多个LAZY加载模式的OneToMany关联,不存在数量限制。你遇到的第二个关联返回空结果的问题,和LAZY模式本身的支持性无关,是二进制主键使用不当引发的连锁问题。
问题根因
- 你所有实体的主键都使用了
binary类型:LAZY加载触发时,Doctrine会从已初始化的主实体实例中取主键值,作为查询关联表的过滤条件。如果PHP侧拿到的binary主键是数据库返回的资源类型、或者在第一次加载第一个关联的过程中被隐式转换/资源被回收,第二个关联查询时传入的过滤参数就是错误值,自然查不到匹配数据。 - 当你把任意一个关联改成EAGER模式时,Doctrine会在主实体初始化阶段,通过JOIN或预查询一次性拉取关联数据,这时候用的是从数据库刚读出的原始主键值,没有被后续逻辑污染,所以查询正常,会给人“改成EAGER就修复了问题”的错觉。
修复步骤
- 第一步:统一处理binary类型主键的返回值
给所有带binary主键的实体添加主键获取方法,把二进制资源统一转为字符串格式,避免资源释放、隐式转换导致的值错误,参考代码:public function getAssociationprocuratorid(): string { if (is_resource($this->associationprocuratorid)) { return stream_get_contents($this->associationprocuratorid); } return (string)$this->associationprocuratorid; }Procuratorsituationhistory、Addresses两个实体的主键getter方法也要做相同的类型转换处理。 - 第二步:在主实体构造函数中初始化集合属性
在Associationprocurators类的构造方法里,提前把两个OneToMany对应的属性初始化为ArrayCollection实例,避免LAZY代理初始化时因为属性为null加载失败:public function __construct() { $this->procuratorsituationhistory = new \Doctrine\Common\Collections\ArrayCollection(); $this->addressesarray = new \Doctrine\Common\Collections\ArrayCollection(); } - 第三步:排查校验(可选)
如果做完前两步还有问题,可以开启Doctrine的SQL日志,观察加载第二个关联时实际执行的SQL,检查传入的AssociationProcuratorId参数值是否和主实体主键一致,绝大多数这类问题都是参数值因为二进制类型转换出错导致的。
注意:你当前的关联映射配置本身没有语法错误,
mappedBy和inversedBy的对应关系是正确的,不需要调整这部分配置。
内容的提问来源于stack exchange,提问作者JLM
相关产品推荐
相关产品推荐

