У меня есть 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);
Repository:
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, но диспетчер объектов не добавляет второй продукт в объект ошибки, который был ранее извлечен.
Одним из решений является отделить объект ошибки до получения их вторым запросом, но в огромном приложении, я не знаю, существует ли объект до или если все продукты доступны. Я думаю, что это обычный случай использования, не зависящий от этого примера, и я не знаю, как решить эту проблему. Я не хочу всегда использовать ленивую загрузку, например. для производительности. Если менеджер объектов добавит второй продукт в объект ошибки, я мог бы использовать функцию соответствия() коллекции, чтобы получить только продукт с идентификатором 1.
Это ошибка в доктрине orm 2.3.4 (также 2.4.0 бета)? Что я могу сделать без очистки диспетчера сущностей или отделить объект ошибки от первого запроса?