Doctrine2单向ManyToOne关联表查询异常:未关联外键
嘿,我太懂你这种“以为手到擒来结果卡壳”的感觉了!你的问题其实出在QueryBuilder的join方式上——你直接关联了实体类,但没告诉Doctrine要用你配置好的实体关联关系,导致数据库不知道怎么把两张表通过service_type_id关联起来。
问题根源
你写的join(ServiceType::class, 't')相当于生成了这样的SQL:
SELECT * FROM server_service ss JOIN service_type t WHERE t.service_type_name = ?
看到没?这里的JOIN没有ON条件!数据库完全不知道怎么关联两张表,自然不会用到你的service_type_id外键。哪怕你在实体里配置了OneToMany关联,QueryBuilder也不会自动帮你推断这个join的关联规则,除非你明确引用实体上的关联属性。
正确的写法(推荐)
假设你的ServerService实体里有一个名为serviceType的关联属性(对应ManyToOne关联的那一端),你应该通过这个属性来join:
return $this->createQueryBuilder('ss') ->join('ss.serviceType', 't') // 引用实体的关联属性,而非直接写实体类 ->where('t.serviceTypeName = :name') ->setParameter('name', $name) // 推荐用setParameter绑定参数,更安全 ->getQuery() ->execute();
这样QueryBuilder会自动根据你实体里配置的关联关系,生成带正确ON条件的SQL,比如:
SELECT * FROM server_service ss JOIN service_type t ON ss.service_type_id = t.id WHERE t.service_type_name = ?
这种方式的好处是复用了实体关联配置,以后如果外键字段名改了,你只需要修改实体映射,不用改QueryBuilder的代码,维护性拉满。
手动指定关联条件(不推荐)
如果你非要手动写关联条件(不建议,因为违背了实体关联的设计初衷),可以用WITH子句明确指定外键关联:
return $this->createQueryBuilder('ss') ->join(ServiceType::class, 't', 'WITH', 'ss.serviceTypeId = t.id') ->where('t.serviceTypeName = :name') ->setParameter('name', $name) ->getQuery() ->execute();
最后检查实体关联配置
别忘了确认你的实体关联配置是正确的,比如ServerService里的关联属性应该类似这样:
// ServerService.php use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass=ServerServiceRepository::class) */ class ServerService { // ...其他属性 /** * @ORM\ManyToOne(targetEntity=ServiceType::class) * @ORM\JoinColumn(name="service_type_id", referencedColumnName="id") */ private $serviceType; // ...getter和setter }
确保@JoinColumn里的name对应数据库里的外键字段service_type_id,referencedColumnName对应ServiceType的主键字段。
内容的提问来源于stack exchange,提问作者guice

