简体   繁体   English

Symfony Doctrine 查询生成器 LIKE 在 PostgreSQL 中不起作用

[英]Symfony Doctrine query builder LIKE not working in PostgreSQL

So I have a UserRepository that contains the following code所以我有一个包含以下代码的 UserRepository

namespace AppBundle\Repository;
use \Doctrine\ORM\EntityRepository;
class UserRepository extends EntityRepository
{
    public function findByRole($role)
    {
        $qb = $this->_em->createQueryBuilder();
        $qb->select('u')
            ->from($this->_entityName, 'u')
            ->where('u.roles LIKE :roles')
            ->setParameter('roles', '%"'.$role.'"%');

        return $qb->getQuery()->getResult();
    }
}

This seems to be working perfectly fine if my database is MySQL but if i change the database to PostgreSQL this query throws the following error如果我的数据库是 MySQL,这似乎工作得很好,但如果我将数据库更改为 PostgreSQL,此查询将引发以下错误

An exception occurred while executing 'SELECT p0_.id AS id_0, p0_.username AS username_1, p0_.password AS password_2, p0_.is_active AS is_active_3, p0_.roles AS roles_4, p0_.name AS name_5, p0_.street AS street_6, p0_.city AS city_7, p0_.state AS state_8, p0_.zip_code AS zip_code_9, p0_.phone_number AS phone_number_10, p0_.dob AS dob_11, p0_.company_name AS company_name_12, p0_.company_slug AS company_slug_13, p0_.company_logo AS company_logo_14, p0_.company_details AS company_details_15, p0_.stripe_customer_id AS stripe_customer_id_16, p0_.created_at AS created_at_17, p0_.updated_at AS updated_at_18 FROM px_user p0_ WHERE p0_.roles LIKE ?'执行'SELECT p0_.id AS id_0, p0_.username AS username_1, p0_.password AS password_2, p0_.is_active AS is_active_3, p0_.roles AS roles_4, p0_.name AS name_5, p0_.street AS street_6, p0_时发生异常.city AS city_7, p0_.state AS state_8, p0_.zip_code AS zip_code_9, p0_.phone_number AS phone_number_10, p0_.dob AS dob_11, p0_.company_name AS company_name_12, p0_.company_slug AS company_slug_company_13_company_company_logo_13 AS company_details_15, p0_.stripe_customer_id AS stripe_customer_id_16, p0_.created_at AS created_at_17, p0_.updated_at AS updated_at_18 FROM px_user p0_WHERE p0_.roles LIKE ?' with params ["%\\"ROLE_EMPLOYER\\"%"]:使用参数 ["%\\"ROLE_EMPLOYER\\"%"]:

SQLSTATE[42883]: Undefined function: 7 ERROR: operator does not exist: json ~~ unknown LINE 1: ...at AS updated_at_18 FROM px_user p0_ WHERE p0_.roles LIKE $1 ^ HINT: No operator matches the given name and argument type(s). SQLSTATE[42883]:未定义的函数:7 错误:运算符不存在:json ~~未知第 1 行:...在 AS updated_at_18 FROM px_user p0_WHERE p0_.roles LIKE $1 ^ 提示:没有运算符匹配给定的名称和参数类型(s)。 You might need to add explicit type casts.您可能需要添加显式类型转换。

This is the first time I am working with PostgreSQL so I am not getting what the problem is.这是我第一次使用PostgreSQL所以我不明白问题是什么。 After playing around with it for a while if I change the generated query to by adding the following piece如果我通过添加以下内容将生成的查询更改为

WHERE 
  p0_.roles::text LIKE '%ROLE_EMPLOYER%'

Everything works fine.一切正常。 Note the ::text .注意::text

So now how can i add that to the query builder so it works with PostgreSQL as well.那么现在我如何将它添加到查询构建器中,以便它也适用于 PostgreSQL。

I solved the problem with the module boldtrn/jsonb-bundle but it created an error depending on the version of Postgres used.我用模块 boldtrn/jsonb-bundle 解决了这个问题,但它根据所使用的 Postgres 版本创建了一个错误。

I also solved the issue without the module by a native query like this :我还通过这样的本机查询解决了没有模块的问题:

public function findEmailsByRole($role)
{
    return $this->_em->getConnection()->executeQuery(
        "SELECT email FROM public.utilisateur WHERE roles::text LIKE :role",
        ['role'=>'%"' . $role . '"%']
    )->fetchAll();
}

You can create your Function Like this你可以像这样创建你的函数

PS: Im Working on PostgreSQL Too PS:我也在研究 PostgreSQL

    public function findByRole($role) {
    $qb = $this->getEntityManager()->createQueryBuilder();
    $qb->select('u')
            ->from($this->getEntityName(), 'u')
            ->where("u.roles LIKE '%$role%'")
    ;

    return $qb->getQuery()->getResult();
}

I solved the problem by using JsonbBundle .我通过使用JsonbBundle解决了这个问题。

Following steps I took to fix it按照我修复它的步骤

$ composer require "boldtrn/jsonb-bundle

Updated the config.yml by adding the following in its respective place.通过在相应位置添加以下内容来更新config.yml

doctrine:
    dbal:
        types:
          jsonb: Boldtrn\JsonbBundle\Types\JsonbArrayType
        mapping_types:
          jsonb: jsonb
    orm:
        dql:
            string_functions:
                JSONB_AG:   Boldtrn\JsonbBundle\Query\JsonbAtGreater
                JSONB_HGG:  Boldtrn\JsonbBundle\Query\JsonbHashGreaterGreater
                JSONB_EX:   Boldtrn\JsonbBundle\Query\JsonbExistence

Changed the roles property to type jsonbroles属性更改为类型jsonb

And inside the repository the following query worked在存储库中,以下查询有效

$query = $this->getEntityManager()->createQuery("SELECT u FROM AppBundle:User u WHERE JSONB_HGG(u.roles , '{}') LIKE '%EMPLOYER%' ");
$users = $query->getResult();
return $users;

The credit goes to Doctrine query postgres json (contains) json_array归功于Doctrine 查询 postgres json (contains) json_array

public function findByRole($role)
{
    $qb = $this->getEntityManager()->createQueryBuilder();
    $qb->select('u')
        ->from($this->getEntityName(), 'u')
        ->where($qb->expr()->like('u.roles', ':roles')
        ->setParameter('roles', $qb->expr()->literal('%'.$role.'%'));

    return $qb->getQuery()->getResult();
}

Replaced your custom string DQL to the QueryBuilder syntax.将您的自定义字符串 DQL 替换为 QueryBuilder 语法。

I don't know if it might be related to the syntax you've got within your like statement: '%".$var."%' , which might bug it.我不知道它是否与您在 like 语句中的语法有关: '%".$var."%' ,这可能会导致错误。 Hope this helps you solve it.希望这可以帮助您解决问题。

Doctrine Querybuilder documentation like : Doctrine Querybuilder 文档,如

 // Example - $qb->expr()->like('u.firstname', $qb->expr()->literal('Gui%')) public function like($x, $y); // Returns Expr\\Comparison instance

Looks like from the PostgreSQL documentation on LIKE , you might need to do this:LIKE 上PostgreSQL 文档看来,您可能需要这样做:

$qb = $this->_em->createQueryBuilder();
$qb->select('u')
    ->from($this->_entityName, 'u')
    ->where('u.roles LIKE :roles')
    ->setParameter('roles', '\'%'.$role.'%\'');

return $qb->getQuery()->getResult();

Essentially having single quotes outside the percent signs by escaping them.基本上通过转义在百分号之外使用单引号。 I'm not sure if that will work, but can you try it?我不确定这是否有效,但你能试试吗?

Building up on @Lou Zito answer :建立在@Lou Zito 的回答上

If you are dealing with Postgres please learn the power of json/b operations!如果您正在处理 Postgres,请学习 json/b 操作的强大功能!

Casting a json/b array into text for like comparison is not a good approach.将 json/b 数组转换为文本以进行类似比较并不是一个好方法。 Cast it into jsonb instead (or even better: change your setup / migration(s) to use jsonb fields directly instead <3)将其转换为 jsonb(或者甚至更好:更改您的设置/迁移以直接使用 jsonb 字段而不是 <3)

You can use ?你可以用? operator, or the contains operator @> as an example.运算符,或以包含运算符@>为例。

See this full list of jsonb operators available Please be aware, that ? 查看可用的 jsonb 运算符的完整列表请注意, ? will get interpreted as doctrine placeholder, you need to use ??将被解释为学说占位符,您需要使用?? to escape it!逃吧!

public function findByRole()
{
    return $query = $this->getEntityManager()
        ->getConnection()
        ->executeQuery(<<<'SQL'
            SELECT id FROM public.user
            WHERE roles::jsonb ?? :role
            ORDER BY last_name, first_name
SQL,
            ['role' => User::ROLE_XYZ]
        )->fetchAllAssociative();
}

Hint: As you can see in the example above, I usually extract roles as public string constants in the User entity for easy access.提示:正如您在上面的示例中看到的,我通常将角色提取为 User 实体中的公共字符串常量,以便于访问。 I strongly recommend that as best practice as well.我也强烈建议将其作为最佳实践。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM