Doctrine 2 ile WHERE IN nasıl kullanılır


126

Bana hata veren aşağıdaki koda sahibim:

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

Kod:

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

Veriler (veya $ ids):

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

DQL sonucu:

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

1
Bunun önerilen yol olduğunu düşünüyorum docs.doctrine-project.org/projects/doctrine-dbal/en/latest/…
martin

Yanıtlar:


115

Bu sorunu araştırırken, aynı sorunla karşılaşan ve bir çözüm arayan herkes için önemli olacak bir şey buldum.

Orijinal gönderiden aşağıdaki kod satırı:

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

Adlandırılmış parametrenin bir dizi olarak sarılması, bağlı parametre numarası sorununa neden olur. Onu dizi sargısından çıkararak:

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

Bu sorun çözülmelidir. Bu, Doctrine'in önceki sürümlerinde bir sorun olabilirdi, ancak 2.0'ın en son sürümlerinde düzeltilmiştir.


5
Bence $qb->expr()->in()sadece Doctrine 2 ORM'de var, Doctrine DBAL'da değil.
martin

3
$qb->expr()->in()gerçekten de DBAL'de
JamesHalsall

345

Bunu yapmanın en kolay yolu, dizinin kendisini bir parametre olarak bağlamaktır:

$queryBuilder->andWhere('r.winner IN (:ids)')
             ->setParameter('ids', $ids);

41
Sadece değil, 2.1'den itibaren
Maciej Pyszyński

7
@ MaciejPyszyński +1. En kolay yollar genellikle en iyisidir!
Andrzej Ośmiałowski

2
Hızlı söz: Bu, varsayılan olarak -> setParameter ('ids', $ ids) ile çalışır ancak -> setParameters ('ids' => $ ids) ile çalışmaz. Birkaç dakika hata ayıklama aldı.
larrydahooster

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

5
Ben de hiç 3th parametre geçirerek önemine işaret etmek istiyorum setParameterkuvveteConnection::PARAM_STR_ARRAY
Luc Wollants

58

ve tamamlanması için dizi çözümü

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

Kesinlikle benim için en iyi çözüm :-)
Francesco Casula

3
Dizge olmayan bir tamsayı dizisine sahipseniz, \ Doctrine \ DBAL \ Connection :: PARAM_INT_ARRAY da kullanılabilir.
Omn


12

Eski bir gönderi olduğunu biliyorum ama birisi için faydalı olabilir. İnts hakkındaki yorumlarda sorulan soruyu ele alarak @Daniel Espendiller yanıtını oylayıp geliştirirdim

Bunun int'ler için düzgün bir şekilde çalışmasını sağlamak için, dizideki değerlerin int türünde olduğundan emin olun, geçmeden önce cast için int yazabilirsiniz ...

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

Symfony 3.4 ve doktrin paketi: 1.8'de seçme / silme için test edildi


8

OP'nin örneğinin DQL ve sorgu oluşturucuyu kullandığını biliyorum, ancak bunu bir denetleyiciden veya depo sınıfının dışından nasıl yapacağımı ararken tökezledim, bu yüzden belki bu başkalarına yardımcı olabilir.

Ayrıca WHERE INdenetleyiciden şu şekilde de yapabilirsiniz :

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

1
Bu, DQL kullanmadan bir yerde yapmanın tamamen kabul edilebilir bir yoludur, ancak sorusu DQL koduyla ilgiliydi. Bana bu kimliklerden yola çıkarak her şeyi basitçe vermekten daha fazlasını yapıyor.
spetz83

6

Bunu yapmanın en iyi yolu - özellikle birden fazla koşul ekliyorsanız - şudur:

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

Değerler diziniz dizeler içeriyorsa, setParameter yöntemini iç içe geçmiş bir dizeyle kullanamazsınız, çünkü tırnak işaretleriniz atlanacaktır!


6

Ben böyle kullandım:

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

5

2016 yılında nasıl yapılacağını bulduk: https://redbeardtechnologies.wordpress.com/2011/07/01/doctrine-2-dql-in-statement/

Alıntı:

İşte bunu doğru şekilde nasıl yapacağınız:

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

Yöntem setParameters, verilen diziyi alacak ve onu "IN" ifadesinde kullanılmak üzere düzgün bir şekilde yerleştirecektir.


2
Bu sorunumu çözdü (etrafındaki parantezler :userids)
Mihai Răducanu

2

Tercih ederim:

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

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

Şunlarla da çalışır:

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

0

Bir dizi değere karşı bir sorgu yapmak zorunda olduğum aynı senaryo ile mücadele ettim.

Aşağıdakiler benim için çalıştı:

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

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

Dizi verisi örneği (dizeler ve tam sayılarla çalıştı):

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

Sorgu örneği (İhtiyacınız olan yere uyarlayın):

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

$q->execute();

0

Bu yıllar sonra, eski bir sitede çalışmak ... Hayatım boyunca ->andWhere()ya da ->expr()->in()çözümleri işe yarayamadı.

Sonunda Doctrine mongodb-odb deposuna baktım ve çok açıklayıcı testler buldu:

public function testQueryWhereIn()
{ 
  $qb = $this->dm->createQueryBuilder('Documents\User');
  $choices = array('a', 'b');
  $qb->field('username')->in($choices);
  $expected = [
    'username' => ['$in' => $choices],
  ];
  $this->assertSame($expected, $qb->getQueryArray());
}

Benim için çalıştı!

Testleri github'da burada bulabilirsiniz . Her türlü saçmalığı açıklığa kavuşturmak için kullanışlıdır.

Not: Kurulumum, yapabildiğim kadarıyla Doctrine MongoDb ODM v1.0.dev kullanıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.