Мениджърът на обекти не очаква поведение с релации (различни заявки)

Имам следната DB/Структура на обект. Така че една грешка може да има множество продукти. Не получавам очакваното поведение в скрипт, ако използвам различни заявки (различно условие за присъединяване). Надявам се, че е по-лесно за разбиране със следния пример на код.

Подгответе база данни:

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)) получавам обекти за грешки само с един продукт, който има идентификатор на продукта 1. Не се използва отложено зареждане. Ако искам сега да получа грешка с всички свързани продукти (findWithProduct(1)), това не работи. Обектът на грешка има напр. два продукта #1 и #2, но мениджърът на обекта не добавя втория продукт към обекта за грешка, който е бил извлечен преди това.

Едно решение е да отделя обекта за грешка, преди да го извлека с второ запитване, но в огромно приложение не знам дали обектът вече съществува преди това или дали всички продукти са налични. Мисля, че това е често срещан случай на употреба, независимо от този пример, и не знам как да разреша този проблем. Не искам винаги да използвам отложено зареждане, напр. за изпълнение. Ако мениджърът на обекта добави втория продукт към обекта за грешка, бих могъл да използвам функцията matching() на колекцията, за да извлека само продукта с идентификатор 1.

Това грешка ли е в doctrine orm 2.3.4 (също 2.4.0 бета)? Какво мога да направя, без да изчистя диспечера на обекти или да отделя обекта за грешка от първата заявка?


person Sandro Keil    schedule 25.08.2013    source източник


Отговори (1)


Виждам от моите съвети за тип, че има и leftJoin, така че мисля, че трябва да използвате leftJoin() вместо това.

person J. Rahmati    schedule 13.01.2014