Symfony4使用findBy查询roles字段返回空结果该如何解决?
问题原因
你的roles字段是JSON类型,Doctrine默认的findBy方法对JSON字段执行的是完全匹配逻辑:
- 如果你传字符串
ROLE_CANDIDATE,会匹配数据库中roles字段值完全等于"ROLE_CANDIDATE"的记录,而你实际存储的是JSON数组格式["ROLE_CANDIDATE","ROLE_USER"],自然匹配不到 - 如果你传数组
['ROLE_CANDIDATE'],会匹配roles完全等于["ROLE_CANDIDATE"]的记录,你存储的数组多了ROLE_USER,同样匹配失败
解决方法
推荐在自定义的UserRepository中编写基于JSON包含的查询方法,步骤如下:
- 首先确保你的MySQL版本 >= 5.7(支持JSON函数),如果项目没有安装Doctrine JSON扩展,先执行安装:
composer require beberlei/doctrineextensions
然后在config/packages/doctrine.yaml中配置JSON_CONTAINS函数:
doctrine: orm: dql: string_functions: JSON_CONTAINS: DoctrineExtensions\Query\Mysql\JsonContains
- 在
App\Repository\UserRepository中添加自定义查询方法:
public function findByRole(string $role): array { return $this->createQueryBuilder('u') ->andWhere('JSON_CONTAINS(u.roles, :role) = 1') // JSON_CONTAINS要求参数为合法JSON格式,用json_encode自动给字符串加双引号 ->setParameter('role', json_encode($role)) ->getQuery() ->getResult(); }
- 修改控制器中的查询逻辑,调用自定义方法:
if ($request->query->get('role')) { $selectedRole = $request->query->get('role'); $users = $this->getDoctrine() ->getRepository(User::class) ->findByRole($selectedRole); } else { $users = $this->getDoctrine() ->getRepository(User::class) ->findAll(); }
可选方案(不安装扩展,用原生SQL)
如果你不想安装额外扩展,可以直接用原生SQL查询:
$conn = $this->getDoctrine()->getConnection(); $sql = 'SELECT * FROM user WHERE JSON_CONTAINS(roles, ?)'; $stmt = $conn->prepare($sql); $stmt->execute([json_encode($selectedRole)]); $users = $stmt->fetchAllAssociative();
如果你使用PostgreSQL数据库,JSON包含查询语法需要调整为
u.roles::jsonb ? :role,参数不需要json_encode,直接传入角色字符串即可。
内容的提问来源于stack exchange,提问作者Ahmed Ferjani
相关产品推荐
相关产品推荐

