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

efzxgjgh  于 2023-05-27  发布在  PHP
关注(0)|答案(5)|浏览(136)

我正在构建一个基于四个参数过滤一些记录的函数:$codigo$anno$term$comite_tecnico。这是我到目前为止所做的:

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();
}

每当我尝试执行查询时,都会得到以下错误:
执行“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?还是n0_anno Like?' with params [“34”,45]:
SQLSTATE[42883]:未定义函数:7错误:操作员不存在:integer ~~未知行1:... dores.norma n0_ WHERE n0_.numero LIKE $1 OR n0_.anno LIKE $2 ^ HINT:没有与给定名称和参数类型匹配的运算符。您可能需要添加显式类型强制转换。
这告诉我,我需要在将其发送到PgSQL DB并执行查询以获得结果之前转换其中的一些参数,但我的问题是,我如何在Doctrine 2 DQL上做到这一点?有可能吗有什么变通的办法吗?我已经找到了this文档,但不知道哪个函数适用,也如何,可以给予我一些帮助或建议围绕这一点?

使用新测试进行编辑

根据用户的建议,我对代码做了一些修改,现在看起来像:

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();
}

但是,再次得到相同的错误:
执行“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?还是n0_anno Like?' with params ["%4%",“4”]:
SQLSTATE[42883]:未定义函数:7错误:操作员不存在:integer ~~未知行1:... dores.norma n0_ WHERE n0_.numero LIKE $1 OR n0_.anno LIKE $2 ^ HINT:没有与给定名称和参数类型匹配的运算符。您可能需要添加显式类型强制转换。
正如你可能注意到的,在这种情况下,参数被传递,应该是:["%4%", "4"]但是为什么会出错?还是没找到

另一个考验

因此,通过使用Doctrine Query Builder并应用一些Doctrine Query Language,我将查询从上面的代码移到了下面的代码中:

$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();

但在这种情况下,我得到这样的消息:
无效的参数号:绑定变量的数量与标记的数量不匹配
如果查询是由OR提出的,应该需要这四个参数吗?

o8x7eapl

o8x7eapl1#

你的第一次尝试对我来说一直都很有效。您可以使用strval()'转换整数。

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

w1e3prcc2#

经过深入的研究,我找到了解决问题的方法,也想和别人分享。我还应该感谢@ErwinBrandstetter,@b.b3rn4rd的时间和支持,以及@Pradeep,它最终给予了我研究的想法,并最终解决了问题,我通过在PostgreSQL中启用隐式铸造支持做到了这一点。
因此,为了启用隐式强制转换,您必须在连接到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';

这就是全部,在我正在使用的当前DB上运行它,并在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);
}

快乐编码!!

sg24os4d

sg24os4d3#

我认为在你最后一次尝试中,原始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 || '%'");

这里还有其他列不是textvarchar吗?把它也扔了。
不知道IDENTITY()函数。也是教义的影响吗
不过,我还是不太了解教义。

vyu0f0g1

vyu0f0g14#

使用doctrine/orm版本2.15.1 + PG版本15和提供CAST扩展的doctrine extension,此代码工作起来很有魅力。

$qb->where($qb->expr()->like('CAST('c.id' AS text)', ':search'));
zaq34kh6

zaq34kh65#

你试图对一个整数使用LIKE,这是没有意义的。
将整数转换为它的文本表示形式。这可能会起作用:

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

相关问题