web-dev-qa-db-fra.com

Comment utiliser WHERE IN avec Doctrine 2

J'ai le code suivant qui me donne l'erreur:

Message: Invalid parameter number: number of bound variables does not match number of tokens 

Code:

public function getCount($ids, $outcome)
{
    if (!is_array($ids)) {
        $ids = array($ids);
    }
    $qb = $this->getEntityManager()->createQueryBuilder();
    $qb->add('select', $qb->expr()->count('r.id'))
       ->add('from', '\My\Entity\Rating r');
    if ($outcome === 'wins') { 
        $qb->add('where', $qb->expr()->in('r.winner', array('?1')));
    }
    if ($outcome === 'fails') {
        $qb->add('where', $qb->expr()->in('r.loser', array('?1')));
    }
    $qb->setParameter(1, $ids);
    $query = $qb->getQuery();
    //die('q = ' . $qb);
    return $query->getSingleScalarResult();
}

Données (ou $ ids):

Array
(
    [0] => 566
    [1] => 569
    [2] => 571
)

Résultat DQL:

q = SELECT COUNT(r.id) FROM \My\Entity\Rating r WHERE r.winner IN('?1')
110
Tjorriemorrie

En recherchant ce problème, j'ai trouvé quelque chose qui serait important pour quiconque se heurterait au même problème et chercherait une solution.

De la publication originale, la ligne de code suivante:

$qb->add('where', $qb->expr()->in('r.winner', array('?1')));

Envelopper le paramètre nommé en tant que tableau provoque le problème du numéro de paramètre lié. En le retirant de son tableau:

$qb->add('where', $qb->expr()->in('r.winner', '?1'));

Ce problème devrait être résolu. Cela aurait pu être un problème dans les versions précédentes de Doctrine, mais cela a été corrigé dans les versions les plus récentes de 2.0.

101
Buster Neece

Le moyen le plus simple de le faire est de lier le tableau lui-même en tant que paramètre:

$queryBuilder->andWhere('r.winner IN (:ids)')
             ->setParameter('ids', $ids);
302
Maciej Pyszyński

et pour compléter la solution de chaîne

$qb->andWhere('foo.field IN (:string)');
$qb->setParameter('string', array('foo', 'bar'), \Doctrine\DBAL\Connection::PARAM_STR_ARRAY);
51

J'ai trouvé que, malgré les indications de la documentation, le seul moyen de faire en sorte que cela fonctionne est la suivante:

$ids = array(...); // Array of your values
$qb->add('where', $qb->expr()->in('r.winner', $ids));

http://groups.google.com/group/doctrine-dev/browse_thread/thread/fbf70837293676fb

23
Jeremy Hicks

Je sais que l'exemple de l'OP utilise DQL et le constructeur de requêtes, mais je suis tombé sur cette solution en cherchant comment le faire depuis un contrôleur ou en dehors de la classe de référentiel. Cela aidera peut-être les autres.

Vous pouvez également créer un WHERE IN à partir du contrôleur de la manière suivante:

// Symfony example
$ids    = [1, 2, 3, 4];
$repo   = $this->getDoctrine()->getRepository('AppBundle:RepoName');
$result = $repo->findBy([
    'id' => $ids
]);
6
Yes Barry

La meilleure façon de procéder, en particulier si vous ajoutez plusieurs conditions, est la suivante:

$values = array(...); // array of your values
$qb->andWhere('where', $qb->expr()->in('r.winner', $values));

Si votre tableau de valeurs contient des chaînes, vous ne pouvez pas utiliser la méthode setParameter avec une chaîne implodée, car vos guillemets seront protégés!

6
ck1

Voici comment je l'ai utilisé:

->where('b.status IN (:statuses)')
->setParameters([
                'customerId' => $customerId,
                'storeId'    => $storeId,
                'statuses'   => [Status::OPEN, Status::AWAITING_APPROVAL, Status::APPROVED]
            ]);
5
George Mylonas

Je sais que c'est un ancien post mais peut être utile pour quelqu'un. Je voterais et améliorerais @Daniel Espendiller pour répondre à la question posée dans les commentaires sur ints

Pour que cela fonctionne correctement pour les int, assurez-vous que les valeurs dans array sont de type int, vous pouvez taper cast to int avant de passer ...

 $qb->andWhere('foo.field IN (:ints)');
 $qb->setParameter('ints', array(1, 2), 
 \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);

Testé pour sélectionner/supprimer dans symfony 3.4 & doctrine-bundle: 1.8

5
Azhar Khattak

Comment faire en 2016: https://redbeardtechnologies.wordpress.com/2011/07/01/doctrine-2-dql-in-statement/

Citation:

Voici comment le faire correctement:

$em->createQuery(“SELECT users FROM Entities\User users WHERE users.id IN (:userids)”)
->setParameters(array(‘userids’ => $userIds));

Le setParameters prendra un tableau et l'implodera correctement pour être utilisé dans l'instruction "IN".

4
Calamity Jane

Je préfère:

$qb->andWhere($qb->expr()->in('t.user_role_id', [
    User::USER_ROLE_ID_ADVERTISER,
    User::USER_ROLE_ID_MANAGER,
]));
2
mnv

J'ai eu du mal avec ce même scénario où je devais faire une requête sur un tableau de valeurs.

Ce qui suit a fonctionné pour moi:

http://docs.doctrine-project.org/projects/doctrine1/en/latest/en/manual/dql-doctrine-query-language.html#where-clause

->andWhereIn("[fieldname]", [array[]])

Exemple de données de tableau (avec des chaînes et des entiers):

$ids = array(1, 2, 3, 4);

Exemple de requête (adaptez-vous où vous en avez besoin):

$q = dataTable::getInstance()
    ->createQuery()
    ->where("name = ?",'John')
    ->andWhereIn("image_id", $ids)
    ->orderBy('date_created ASC')
    ->limit(100);

$q->execute();
0
Mortolian
->where($qb->expr()->in('foo.bar', ':data'))
            ->setParameter('participants', $data);

Fonctionne également avec:

 ->andWhere($qb->expr()->in('foo.bar', ':users'))
                ->setParameter('data', $data);
0
John Smith