2012-10-08 7 views
15

少なくとも2つの左ジョインで複雑なリクエストをページ付けしたいのですが、私が使っているページングバンドル(Dopprine)では結果を数える方法(which is needed for the pagination process)を教えられません。この例外を持ち続ける。ここでDoctrine:左ジョイントのページネック

Cannot count query which selects two FROM components, cannot make distinction

教義QueryBuilderで構築されたサンプルの要求です。

public function findGroupsByUser(User $user, $listFilter, $getQuery = false, $order = 'ASC') 
{ 
    $query = $this->createQueryBuilder('r') 
     ->select('r as main,g') 
     ->select('r as main,g, count(gg) as members') 
     ->leftjoin('r.group', 'g') 
     ->innerjoin('MyBundle:GroupMemberRel', 'gg', 'WITH', 'r.group = gg.group') 
     ->addGroupBy('g.groupId') 
     ->add('orderBy', 'g.name ' . $order); 
    if ($getQuery == true) { 
     return $query; 
    } 

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

それから私はknp_paginatorサービスにこの要求を与える、と私は例外

$groupQuery = $this->em->getRepository('MyBundle:GroupMemberRel')->findGroupsByUser($user, $listFilter, true); 
    $paginator = $this->container->get('knp_paginator'); 
    /* @var $groups Knp\Component\Pager\Pagination\PaginationInterface */ 
    $groups = $paginator->paginate(
     $groupQuery, $this->container->get('request')->query->get('page', 1), 10 /* limit per page */ 
    ); 

に複雑な要求を超えるページ付けする方法上の任意のアイデアを持って、その後、私はこの使用かなり確信しています大文字 - 小文字は一般的ですが、改ページ後に私の結果を水和させたくありません。

+0

Pagerfantaのdoctrine ORMアダプタは、奇妙なクエリを処理できる必要があります。 https://github.com/whiteoctober/Pagerfanta – AdrienBrault

+0

この質問は変わっていません。私は単純にknpページャーでそれを行う方法があると確信しています。多分、私はページャーにもっと深く見てください。 –

+0

私はこの問題に直面して..どのような解決策? – tttony

答えて

20

が、そこでは良い解決策ですこれを使用する。追加することを忘れないでください。

+5

みんな、**配列(' distinct '=> false)に注意してください。 – Eugene

14

元の質問のエンティティを理解することは難しいですが、私はこの同じ問題に遭遇しましたが、実際に解決できました。

あなたはこのような実体があるとします。

class User 
    { 
    // ... 
    /** 
    * @ORM\OneToMany(targetEntity="Registration", mappedBy="user") 
    */ 
    private $registrations; 
    // ... 
    } 

重要なことは、それが別のエンティティと1対多の関係を有することである、とあなたが経由してそれに参加することができるようにしたいです何らかの理由でQueryBuilderを使用します(たとえば、クエリにHAVING句を追加して、これらのエンティティを1つ以上持つエンティティのみを選択したい場合など)。

あなたの元のコードは次のようになります

:これは、例外がスローされます

$qb = $this->createQueryBuilder(); 

    $query = $qb 
    ->select('u') 
    ->add('from', '\YourBundle\ORM\Model\User u') 
    ->leftJoin('\YourBundle\ORM\Model\Registration', 'r', 'WITH', 'u.id = r.user') 
    ->groupBy('u.id') 
    ->having($qb->expr()->gte($qb->expr()->count('u.registrations'), '1') 
    ->getQuery(); 

Cannot count query which selects two FROM components, cannot make distinction

は、この問題を解決するには、QueryBuilderは一つだけを持っているように、コンポーネント「から」問合せをリライト - 正確に例外が示すように - 結合をインラインで移動します。同様に:

$qb = $this->createQueryBuilder(); 

    $query = $qb 
    ->select('u') 
    ->add('from', '\YourBundle\ORM\Model\User u LEFT JOIN u.registrations r') 
    ->groupBy('u.id') 
    ->having($qb->expr()->gte($qb->expr()->count('r'), '1') 
    ->getQuery(); 

DoctrineのPaginatorクラスでうまく動作する必要があります。他のバンドルは必要ありません。また、結合の簡略構文にも注意してください。 Doctrineでは、マッピングが既に何であるかを知っているので、結合されたエンティティを明示的に指定することはできません(できるだけ)。

これが誰かを助けてくれることを願っています。そこにはこの問題がたくさんありません。内部の処理方法については、@halfer's comment hereをご覧ください。 、あなたは何をしているか、基本的に https://github.com/KnpLabs/KnpPaginatorBundle/blob/master/Resources/doc/manual_counting.md

$paginator = new Paginator; 

$count = $entityManager 
->createQuery('SELECT COUNT(c) FROM Entity\CompositeKey c') 
->getSingleScalarResult(); 

$query = $entityManager 
->createQuery('SELECT c FROM Entity\CompositeKey c') 
->setHint('knp_paginator.count', $count); 

$pagination = $paginator->paginate($query, 1, 10, array('distinct' => false)); 

、あなたがあなた自身の「数」クエリを作成し、KNPのページネータに指示されている。これについての答えを探している人のために

+3

これは受け入れられた回答です! – newbie

+0

私はあなたの提案を試みましたが、うまくいきません。 https://gist.github.com/TrkiSF2/16d64a8aec846f4053a5アプローチを変更する必要性をさらに調査することはできません:( – EnchanterIO

+0

あなたが持っている問題は、参加とは無関係ですが、むしろHAVINGを使うように聞こえます。提供されているコードスニペットから、意図が何であるかは不明ですが、1つ以上のログインを持つユーザだけを取得しようとしているのでしょうか?もしそうなら、 ' - > 'HAVING'の代わりに(' lh.user IS NOT NULL ') 'を実行してください。 – futureal

0

上記の答えで指定された方法で通常のマップされたエンティティを使用していない場合、ジョインは結果セットに追加のコンポーネントを作成します。つまり、スカラー結果ではないため、集合を数えることはできません。

したがって、キーは結果セットを1つのコンポーネントに保持しているため、スカラー結果を生成してカウントすることができます。

実行時に通常のフィールドをエンティティマッピングに変換できます。これにより、他のエンティティに無作為に参加している場合でも、返されるコンポーネントが1つのみのクエリを記述できます。 「その他のエンティティ」は、追加のルートエンティティまたは結果の余分なコンポーネントではなく、メインエンティティの子になります。

以下の例は、1対1のマッピングを示しています。私はもっ​​と複雑なマッピングを試していませんが、これで成功すれば可能であるはずです。登録エンティティには、ユーザIDを含むuserというフィールドがありますが、マッピングされたエンティティではなくプレーンフィールドのみです。

(これは、実施例から変更なくそのままテストされていないれた - そう擬似コードとして扱う)

$queryBuilder // The query builder already has the other entities added. 
     ->innerJoin('r.user', 'user') 
    ; 


    $mapping['fieldName'] = 'user'; 
    $mapping['targetEntity'] = '\YourBundle\ORM\Model\User'; 
    $mapping['sourceEntity'] = '\YourBundle\ORM\Model\Registration'; 
    $mapping['sourceToTargetKeyColumns'] = array('user' => 'id'); 
    $mapping['targetToSourceKeyColumns'] = array('id' => 'user'); 
    $mapping['fetch'] = 2; 
    $mapping['joinColumns'] = array(
     array(
      'name' => 'user', 
      'unique' => false, 
      'nullable' => false, 
      'onDelete' => null, 
      'columnDefinition' => null, 
      'referencedColumnName' => 'id', 
     ) 
    ); 
    $mapping['mappedBy'] = 'user'; 
    $mapping['inversedBy'] = null; // User doesn't have to link to registrations 
    $mapping['orphanRemoval'] = false; 
    $mapping['isOwningSide'] = true; 
    $mapping['type'] = ClassMetadataInfo::MANY_TO_ONE; 

    $vm = $this->em->getClassMetadata('YourBundle:Registration'); 

    $vm->associationMappings["user"] = $mapping; 

注:私はKNP PagerFantaをしない使用していた - しかし、問題は、私は教義でありますこれがどこでもうまくいくと思います。

2

doctrine/dbalを2.5にアップデートすると、この問題が修正されました。

関連する問題