简体   繁体   English

Doctrine2 + Symfony2:在绑定到DQL查询之前强制转换值

[英]Doctrine2 + Symfony2: Cast values before bind to DQL query

I'm building a function for filter some records based on four parameters: $codigo , $anno , $term and $comite_tecnico . 我正在构建一个函数,用于基于四个参数过滤一些记录: $codigo$anno$term$comite_tecnico This is what I build until now: 这是我到目前为止构建的:

public function filtrarNorma($codigo = null, $anno = null, $term = null, $comite_tecnico = null)
{
    $qb = $this->getEntityManager()->createQueryBuilder();
    $qb
            ->select('n')
            ->from("AppBundle:Norma", "n");

    if ($codigo != NULL) {
        $qb->where($qb->expr()->like('n.numero', ':codigo'));
        $qb->setParameter('codigo', '%' . $codigo . '%');
    }

    if ($anno != NULL) {
        $qb->orWhere($qb->expr()->like('n.anno', ':anno'));
        $qb->setParameter('anno', '%' . $anno . '%');
    }

    if ($term != NULL) {
        $qb->orWhere($qb->expr()->like('n.nombre', ':term'));
        $qb->setParameter('term', '%' . $term. '%');
    }

    if ($comite_tecnico != NULL) {
        $qb->orWhere($qb->expr()->like('n.comite_tecnico', ':comite_tecnico'));
        $qb->setParameter('comite_tecnico', '%' . $comite_tecnico . '%');
    }

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

Any time I try to perform a query I get this error: 每当我尝试执行查询时,都会出现此错误:

An exception occurred while executing 'SELECT n0_.numero AS numero0, n0_.anno AS anno1, n0_.id AS id2, n0_.nombre AS nombre3, n0_.activo AS activo4, n0_.comite_tecnico_id AS comite_tecnico_id5 FROM nomencladores.norma n0_ WHERE n0_.numero LIKE ? 执行'SELECT n0_.numero AS numero0,n0_.anno AS anno1,n0_.id AS id2,n0_.nombre AS nombre3,n0_.activo AS activo4,n0_.comite_tecnico_id AS comite_tecnico_id5 FROM nomencladores.NORma n0 numero喜欢吗? OR n0_.anno LIKE ?' 或n0_.anno喜欢吗? with params ["34", 45]: 带有参数[“ 34”,45]:

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

That's telling me that I need to cast some of those parameters before send it to the PgSQL DB and execute the query to get results but my question is, how I do that on Doctrine2 DQL? 这告诉我,在将其发送到PgSQL DB并执行查询以获取结果之前,需要转换其中的一些参数,但我的问题是,如何在Doctrine2 DQL上执行此操作? It's possible? 这是可能的? Any workaround or trick or something else? 有任何解决方法或技巧吗? I've found this documentation but don't know which function apply and also how, can any give me some help or advice around this? 我找到了文档,但不知道适用哪个功能以及如何应用,有什么可以给我一些帮助或建议吗?

Edit with new tests 使用新测试进行编辑

After users suggestions I made some changes to my code and now it looks like: 在用户提出建议之后,我对代码做了一些更改,现在看起来像:

public function filtrarNorma($codigo = null, $anno = null, $term = null, $comite_tecnico = null)
{
    $qb = $this->getEntityManager()->createQueryBuilder();
    $qb
            ->select('n')
            ->from("AppBundle:Norma", "n");

    if ($codigo != NULL) {
        $qb->where($qb->expr()->like('n.numero', ':codigo'));
        $qb->setParameter('codigo', '%'.$codigo.'%', PDO::PARAM_STR);
    }

    if ($anno != NULL) {
        $qb->orWhere($qb->expr()->like('n.anno', ':anno'));
        $qb->setParameter('anno', $anno, PDO::PARAM_INT);
    }

    if ($term != NULL) {
        $qb->orWhere($qb->expr()->like('n.nombre', ':term'));
        $qb->setParameter('term', '%'.$term.'%', PDO::PARAM_STR);
    }

    if ($comite_tecnico != NULL) {
        $qb->orWhere($qb->expr()->like('IDENTITY(n.comite_tecnico)', ':comite_tecnico'));
        $qb->setParameter('comite_tecnico', '%'.$comite_tecnico.'%', PDO::PARAM_INT);
    }

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

But once again, get the same error: 但是,再次出现相同的错误:

An exception occurred while executing 'SELECT n0_.numero AS numero0, n0_.anno AS anno1, n0_.id AS id2, n0_.nombre AS nombre3, n0_.activo AS activo4, n0_.comite_tecnico_id AS comite_tecnico_id5 FROM nomencladores.norma n0_ WHERE n0_.numero LIKE ? 执行'SELECT n0_.numero AS numero0,n0_.anno AS anno1,n0_.id AS id2,n0_.nombre AS nombre3,n0_.activo AS activo4,n0_.comite_tecnico_id AS comite_tecnico_id5 FROM nomencladores.NORma n0 numero喜欢吗? OR n0_.anno LIKE ?' 或n0_.anno喜欢吗? with params ["%4%", "4"]: 带有参数[“%4%”,“ 4”]:

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

And as you may notice in this case params are passed as should be: ["%4%", "4"] but why the error? 您可能会注意到,在这种情况下,应按如下所示传递参数: ["%4%", "4"]但是为什么会出错? Still not getting where it's 仍然无法到达目的地

Another test 另一个测试

So, getting ride of Doctrine Query Builder and applying some Doctrine Query Language I moved the query from the code above to this one: 因此,乘坐Doctrine Query Builder并应用某种Doctrine查询语言,我将查询从上面的代码移到了这一代码:

    $em = $this->getEntityManager();
    $query = $em->createQuery("SELECT n from AppBundle:Norma n WHERE n.numero LIKE '%:codigo%' OR n.anno LIKE '%:anno%' OR n.nombre LIKE '%:term%' OR IDENTITY(n.comite_tecnico) LIKE '%:comite_tecnico%'");
    $query->setParameters(array(
            'codigo' => $codigo,
            'anno' => $anno,
            'term' => $term,
            'comite_tecnico' => $comite_tecnico
        ));

    return $query->getResult();

But in this case I get this message: 但是在这种情况下,我收到以下消息:

Invalid parameter number: number of bound variables does not match number of tokens 无效的参数编号:绑定变量的数量与令牌的数量不匹配

If the query is made by OR should be the four parameters required? 如果查询是通过OR是否需要四个参数?

Your first try actually works for me all the time. 您的第一次尝试实际上一直对我有用。 You can convert your integers using strval()'. 您可以使用strval()'转换整数。

'%' . strval($anno) . '%';

After a deep research I've found the solution to my problem and want to share with others too. 经过深入研究,我找到了解决问题的方法,并且也希望与他人分享。 I should said also thanks to @ErwinBrandstetter, @b.b3rn4rd for their time and support and to @Pradeep which finally give me the idea for research and finally get problem fixed and I did by enabling implicit casting support in PostgreSQL. 我还应该感谢@ ErwinBrandstetter,@ b.b3rn4rd的时间和支持以及@Pradeep,它们最终使我有了研究的思路,并最终解决了问题,我在PostgreSQL中启用了隐式转换支持。

For enable implicit casts you must therefore execute the following commands in your PostgreSQL console when connected to the template1 database, so that any database created afterward will come with the required CASTs (if your database is already created, execute the commands in your database as well): 因此,对于启用隐式强制转换,您必须在连接到template1数据库时在PostgreSQL控制台中执行以下命令,以便以后创建的任何数据库都将带有必需的CAST(如果已经创建了数据库,则也要在数据库中执行命令):

CREATE FUNCTION pg_catalog.text(integer) RETURNS text STRICT IMMUTABLE LANGUAGE SQL AS 'SELECT textin(int4out($1));';
CREATE CAST (integer AS text) WITH FUNCTION pg_catalog.text(integer) AS IMPLICIT;
COMMENT ON FUNCTION pg_catalog.text(integer) IS 'convert integer to text';

CREATE FUNCTION pg_catalog.text(bigint) RETURNS text STRICT IMMUTABLE LANGUAGE SQL AS 'SELECT textin(int8out($1));';
CREATE CAST (bigint AS text) WITH FUNCTION pg_catalog.text(bigint) AS IMPLICIT;
COMMENT ON FUNCTION pg_catalog.text(bigint) IS 'convert bigint to text';

That's all, after running that on the current DB I'm using and also on template1 for future ones and keeping conditions on my code as follow, all works fine and without any errors: 就是这样,在我正在使用的当前数据库上运行该数据库,并在template1运行以后的数据库,并在我的代码上保持如下所示的条件之后,所有这些都可以正常运行并且没有任何错误:

if ($codigo != null) {
    $qb->where($qb->expr()->like('n.numero', ':codigo'));
    $qb->setParameter('codigo', '%'.$codigo.'%', PDO::PARAM_STR);
}

if ($anno != null) {
    $qb->orWhere($qb->expr()->like('n.anno', ':anno'));
    $qb->setParameter('anno', '%'.$anno.'%', PDO::PARAM_STR);
}

if ($term != null) {
    $qb->orWhere($qb->expr()->like('n.nombre', ':term'));
    $qb->setParameter('term', '%'.$term.'%', PDO::PARAM_STR);
}

if ($comite_tecnico != null) {
    $qb->orWhere($qb->expr()->like('IDENTITY(n.comite_tecnico)', ':comite_tecnico'));
    $qb->setParameter('comite_tecnico', '%'.$comite_tecnico.'%', PDO::PARAM_STR);
}

Happy coding!! 编码愉快!!

You're trying to use LIKE on an integer, which doesn't make sense. 您正在尝试对整数使用LIKE ,这没有任何意义。

Cast the integer to its text representation. 将整数强制转换为其文本表示形式。 This might work: 这可能起作用:

$qb->where($qb->expr()->like('CAST(n.numero AS text)', ':codigo'));

I think in your last try the raw SQL string should look like this: 我认为在您的上一次尝试中,原始SQL字符串应如下所示:

$query = $em->createQuery("SELECT n.*
    FROM  nomencladores.norma n
    WHERE n.numero LIKE '%' || :codigo || '%' OR
          cast(n.anno AS text) LIKE '%' || :anno || '%' OR
          n.nombre LIKE '%' || :term || '%' OR
          IDENTITY(n.comite_tecnico) LIKE '%' || :comite_tecnico || '%'");

Any other column here not text or varchar ? 这里还有其他列不是textvarchar吗? Cast it, too. 也投下吧。
Don't know the IDENTITY() function. 不知道IDENTITY()函数。 A spillover from Doctrine, as well? 也是从学说的溢出?
Still, I don't know much about Doctrine. 不过,我对教义知之甚少。

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

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