次のDB/Entity Structureがあります。そのため、バグには複数の製品が含まれる場合があります。異なるクエリ (異なる結合条件) を使用すると、スクリプトで期待される動作が得られません。次のコード例で理解しやすくなれば幸いです。
データベースの準備:
INSERT INTO `bug` (`bug_id`, `description`, `status`) VALUES
    (1, 'Entity manager doesnt work as expected', 'open'),
    (2, 'Dotrine ORM issue', 'closed'),
    (3, 'Another bug', 'closed');
INSERT INTO `product` (`product_id`, `name`) VALUES
    (1, 'Doctrine 2'),
    (2, 'Zend Framwork 2'),
    (2, 'Another product');
INSERT INTO `bug_product` (`bug_id`, `product_id`) VALUES
    (1, 1),
    (1, 2),
    (2, 2),
    (3, 1),
    (3, 3);
リポジトリ:
class BugRepository extends \Doctrine\ORM\EntityRepository
{
    // here we want all bugs with only one product e.g. for a product overview
    public function findFilteredByProduct($productId)
    {
        $qb = $this->createQueryBuilder('bug')
            ->addSelect('product')
            ->join('bug.product', 'product')
            ->where('product = :productid')
            ->setParameter('productid', $productId);
        $query = $qb->getQuery();
        return $query->getResult();
    }
    // here we want all products for a bug, e.g. for bug details
    public function findWithProduct($bugId)
    {
        $qb = $this->createQueryBuilder('bug')
            ->addSelect('product')
            ->join('bug.product', 'product')
            ->where('bug.bugId = :bugId')
            ->setParameter('bugId', $bugId);
        $query = $qb->getQuery();
        return $query->getResult();
    }
}
コントローラ:
class IndexController extends \Zend\Mvc\Controller\AbstractActionController
{
    public function testAction()
    {
         // assumed that $repoBug is initialized
        // only bugs which have an association with product #1
        $bugs = $repoBug->findFilteredByProduct(1);
         /* @var $bug \Bug\Entity\Bug*/
        foreach ($bugs as $bug) {
            echo 'Bug #' . $bug->getBugId() . '<br/>';
            /* @var $p \Bug\Entity\Product */
            foreach ($bug->getProduct() as $p) { // here only product #1 for all bugs available, thats fine
                echo '#' . $p->getProductId() . ' ' . $p->getName() . '<br/>';
            }
        }
        // get bug #1 with all associated products
        $bug1 = $repoBug->findWithProduct(1);
        $bug1 = reset($bug1);
        /* @var $p \Bug\Entity\Product */
        foreach ($bug1->getProduct() as $p) { // here also only product #1 available, thats wrong, it should also product #2 available e.g. for bug #1
            echo '#' . $p->getProductId() . ' ' . $p->getName() . '<br/>';
        }
         // some other stuff
    }
}
実行されたクエリ:
findFilteredByProduct(1):
SELECT
    b0_.bug_id AS bug_id0,
    b0_.description AS description1,
    b0_. STATUS AS status2,
    p1_.product_id AS product_id3,
    p1_. NAME AS name4
FROM
    bug b0_
INNER JOIN bug_product b2_ ON b0_.bug_id = b2_.bug_id
INNER JOIN product p1_ ON p1_.product_id = b2_.product_id
WHERE
    p1_.product_id = ?
findWithProduct(1):
SELECT
    b0_.bug_id AS bug_id0,
    b0_.description AS description1,
    b0_. STATUS AS status2,
    p1_.product_id AS product_id3,
    p1_. NAME AS name4
FROM
    bug b0_
INNER JOIN bug_product b2_ ON b0_.bug_id = b2_.bug_id
INNER JOIN product p1_ ON p1_.product_id = b2_.product_id
WHERE
    b0_.bug_id = ?
説明:
最初のクエリ (findFilteredByProduct(1)) で、製品 ID が 1 の製品が 1 つだけのバグ エンティティを取得します。遅延読み込みは使用されません。関連するすべての製品 (findWithProduct(1)) でバグを取得したい場合、機能しません。バグ エンティティには、たとえば 2 つの製品 #1 と #2 がありますが、エンティティ マネージャは、以前に取得したバグ エンティティに 2 番目の製品を追加しません。
1 つの解決策は、2 番目のクエリでバグ エンティティを取得する前にバグ エンティティをデタッチすることですが、巨大なアプリケーションでは、エンティティが以前に存在するかどうか、またはすべての製品が利用可能かどうかはわかりません。これは、この例とは無関係の一般的な使用例だと思いますが、この問題を解決する方法がわかりません。パフォーマンスなどのために、常に遅延読み込みを使用したくありません。エンティティ マネージャが 2 番目の製品をバグ エンティティに追加する場合、コレクションの matching() 関数を使用して、ID 1 の製品のみを取得できます。
これは doctrine orm 2.3.4 (同じく 2.4.0 ベータ版) のバグですか? エンティティ マネージャをクリアせずに、または最初のクエリからバグ エンティティを切り離すために何ができますか?