Symfony 6.2:访问OneToMany集合时出现「主键langId缺失值」错误
解决Doctrine关联查询时的复合主键缺失问题
我定义了AccessoryGroup实体,通过OneToMany关联到AccessoryPart实体。获取AccessoryGroup列表操作正常,但访问其关联的accessoryPartList集合时,系统抛出错误:
Missing value for primary key langId on App\Entity\AccessoryGroup
相关代码
AccessoryGroup.php
#[ORM\Entity(repositoryClass: AccessoryGroupRepository::class, readOnly: true)] class AccessoryGroup { #[ORM\Id] #[ORM\GeneratedValue(strategy: "NONE")] #[ORM\Column(name: "accessory_group_id" , type: "string", length: 10, nullable: false)] private string $accessoryGroupId = ""; #[ORM\Id] #[ORM\GeneratedValue(strategy: "NONE")] #[ORM\Column(type: "string", length: 2, nullable: false, options: ["default" => "DE"])] private string $langId = "DE"; #[ORM\Column(type: "string", length: 50, nullable: false)] private string $title = ""; #[ORM\Column(name: "last_update", type: "datetime", columnDefinition: "DATETIME default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP")] private DateTime $lastUpdate; #[ORM\OneToMany( mappedBy: "accessoryGroup", targetEntity: "AccessoryPart")] private Collection $accessoryPartList; public function __construct() { $this->accessoryPartList = new ArrayCollection(); } /** getters **/ ... /** * @return Collection */ public function getAccessoryPartList(): Collection { return $this->accessoryPartList; } }
AccessoryPart.php
#[ORM\Entity(repositoryClass: AccessoryPartRepository::class, readOnly: true)] class AccessoryPart { #[ORM\Id] #[ORM\ManyToOne(targetEntity: "AccessoryGroup", inversedBy: "accessoryPartList")] #[ORM\JoinColumn(name: "accessory_group_id", referencedColumnName: "accessory_group_id", nullable: false)] private ?AccessoryGroup $accessoryGroup = null; #[ORM\Id] #[ORM\ManyToOne(targetEntity: "Articles")] #[ORM\JoinColumn(name: "article_part_id", referencedColumnName: "article_id", nullable: false)] private ?Articles $articlePart = null; #[ORM\Id] #[ORM\ManyToOne(targetEntity: "Manufacturers")] #[ORM\JoinColumn(name: "manufacturer_part_id", referencedColumnName: "manufacturer_id", nullable: false)] private ?Manufacturers $manufacturerPart = null; #[ORM\Id] #[ORM\ManyToOne(targetEntity: "Articles")] #[ORM\JoinColumn(name: "article_accessory_id", referencedColumnName: "article_id", nullable: false)] private ?Articles $articleAccessory = null; #[ORM\Id] #[ORM\ManyToOne(targetEntity: "Manufacturers")] #[ORM\JoinColumn(name: "manufacturer_acc_id", referencedColumnName: "manufacturer_id", nullable: false)] private ?Manufacturers $manufacturerAcc = null; #[ORM\Column(type: "integer", nullable: true, options: ["default" => 0])] private int $flag = 0; #[ORM\Column(name: "last_update", type: "datetime", columnDefinition: "DATETIME default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP")] private DateTime $lastUpdate; /** getters *// }
AccessoryGroupRepository.php
/** * @param $articleId * @param $language * @return AccessoryGroup[] */ public function getAccessoryFromPart($articleId, $language): array { return $this->createQueryBuilder('ag') ->where('ag.langId = :lng') ->setParameter('lng', $language) ->distinct() ->getQuery() ->getResult(); }
控制器代码
$accessoryGList = $agr->getAccessoryFromPart($articleId, $this->sesCustomer['lang'] ?? "DE"); // 结果正常,返回两行数据 echo "Size: ".sizeof($accessoryGList[0]->getAccessoryPartList()); // <== 触发错误
问题原因及解决方法
核心问题
AccessoryGroup使用复合主键(accessoryGroupId + langId),但AccessoryPart关联AccessoryGroup时,只配置了accessory_group_id这一个主键字段。Doctrine无法通过单一主键定位完整的AccessoryGroup实体,加载关联集合时会找不到langId的值,从而抛出错误。
修复步骤
补全AccessoryPart的关联映射
修改AccessoryPart中accessoryGroup的关联定义,添加复合主键的第二个字段映射,确保Doctrine能获取完整的主键信息:#[ORM\Id] #[ORM\ManyToOne(targetEntity: "AccessoryGroup", inversedBy: "accessoryPartList")] #[ORM\JoinColumns([ new ORM\JoinColumn(name: "accessory_group_id", referencedColumnName: "accessory_group_id", nullable: false), new ORM\JoinColumn(name: "lang_id", referencedColumnName: "langId", nullable: false) ])] private ?AccessoryGroup $accessoryGroup = null;注意:需确保数据库中
accessory_part表存在lang_id字段,且与accessory_group表的langId字段对应。提前加载关联数据(可选)
为避免懒加载时的额外查询,可在Repository查询中提前关联并获取accessoryPartList集合:public function getAccessoryFromPart($articleId, $language): array { return $this->createQueryBuilder('ag') ->where('ag.langId = :lng') ->setParameter('lng', $language) ->leftJoin('ag.accessoryPartList', 'apl') ->addSelect('apl') ->distinct() ->getQuery() ->getResult(); }验证主键Getter方法完整性
确保AccessoryGroup的两个主键字段都有对应的Getter方法,Doctrine需要通过这些方法获取主键值构建关联查询:public function getAccessoryGroupId(): string { return $this->accessoryGroupId; } public function getLangId(): string { return $this->langId; }
内容的提问来源于stack exchange,提问作者Adi
相关产品推荐
相关产品推荐

