Symfony API Platform用Doctrine扩展过滤同表关联账户实体问题
问题原因
- 你使用了
innerJoin关联accountUsers和parentAccount,会直接过滤两类符合要求的账户:本身和当前用户关联、但没有父账户的根账户;本身没有和当前用户关联、但父账户和当前用户关联的子账户。 - 你用
innerJoin强制要求所有关联必须存在,当Doctrine解析到不存在的关联记录时,自动生成的别名没有被正确注册,就会抛出该paaccountUsers_a2未定义错误。
修复方案
两层级关系场景(仅需返回关联账户+直接子账户)
直接修改原有扩展代码即可:
$alias = $queryBuilder->getRootAliases()[0]; $queryBuilder // 左连接当前账户的关联用户记录,避免过滤无直接关联的子账户 ->leftJoin(sprintf('%s.accountUsers', $alias), 'au') // 左连接当前账户的父账户,避免过滤无父级的根账户 ->leftJoin(sprintf('%s.parentAccount', $alias), 'pa') // 左连接父账户的关联用户记录 ->leftJoin(sprintf('%s.accountUsers', 'pa'), 'paau') ->andWhere($queryBuilder->expr()->orX( 'au.user = :current_user', 'paau.user = :current_user' )) ->setParameter('current_user', $currentUser);
无限层级关系场景(需返回关联账户下所有子/孙/多级子账户)
建议使用递归CTE实现,性能远高于多层join,以MySQL为例:
$alias = $queryBuilder->getRootAliases()[0]; $em = $queryBuilder->getEntityManager(); $connection = $em->getConnection(); // 先查询当前用户直接关联的所有账户ID $linkedAccountIds = $connection->fetchFirstColumn( 'SELECT account_id FROM account_user WHERE user_id = ?', [$currentUser->getId()] ); if (empty($linkedAccountIds)) { // 无关联账户直接返回空结果 $queryBuilder->andWhere('1 = 0'); return; } // 递归查询所有层级的子账户ID $recursiveSql = <<<SQL WITH RECURSIVE account_hierarchy AS ( SELECT id FROM account WHERE id IN (?) UNION ALL SELECT a.id FROM account a INNER JOIN account_hierarchy ah ON a.parent_account_id = ah.id ) SELECT id FROM account_hierarchy SQL; $allAllowedIds = $connection->fetchFirstColumn($recursiveSql, [implode(',', $linkedAccountIds)]); $queryBuilder ->andWhere(sprintf('%s.id IN (:allowed_ids)', $alias)) ->setParameter('allowed_ids', $allAllowedIds);
补充说明
请先确认你的Account实体配置正确:parentAccount字段为ManyToOne关联到Account实体,反向关联children为OneToMany,属性名和代码中使用的一致即可。
内容的提问来源于stack exchange,提问作者Lucas Estebe
相关产品推荐
相关产品推荐

