У меня странная ошибка Symfony/Doctrine. Моя структура объектов выглядит следующим образом
class ClassA {
/**
* @ORM\ManyToOne(targetEntity="My\CoreBundle\Entity\ClassB", inversedBy="classAs", cascade={"persist"})
* @ORM\JoinColumn(nullable=false)
*/
private $classB;
}
class ClassB {
/**
* @ORM\OneToMany(targetEntity="My\CoreBundle\Entity\ClassA", mappedBy="classB", cascade={"persist", "remove"})
*/
private $classAs;
/**
* @ORM\ManyToOne(targetEntity="My\CoreBundle\Entity\ClassC", inversedBy="classBs")
* @ORM\JoinColumn(nullable=false)
*/
private $classC;
}
class ClassC {
/**
* Inverse Side
* @ORM\OneToMany(targetEntity="My\CoreBundle\Entity\ClassB", mappedBy="classC", cascade={"persist", "remove"})
*/
private $classBs;
/**
* Inverse Side
* @ORM\OneToMany(targetEntity="My\CoreBundle\Entity\ClassD", mappedBy="classCs", cascade={"persist", "remove"})
*/
private $classDs;
}
class ClassD {
/**
* @ORM\ManyToOne(targetEntity="My\CoreBundle\Entity\ClassC", inversedBy="classDs")
* @ORM\JoinColumn(nullable=false)
*/
private $classC;
}
Я знаю, что в базе данных ClassA (id = 566208) связан с ClassD (id = 16286).
У меня этот очень простой метод в ClassARepository.
class ClassARepository extends EntityRepository
{
public function myMethod()
{
$builder = $this->createQueryBuilder('classA');
$query = $builder->getQuery();
$classAs = $query->getResult();
echo "<pre>";
foreach ($classAs as $classA) {
if ($classA->getId() == 566208)
{
echo "classA 566208\n";
$classDs = $classA->getClassB()->getClassC()->getClassDs();
$found = false;
foreach ($classDs as $classD) {
if (16286 == $classD->getId()) {
$found = true;
echo "INFO 16286 found\n";
}
}
if (false == $found) echo "ERROR 16286 Not found\n";
}
}
echo "</pre>";
}
}
Когда я вызываю этот метод в контроллере, нет проблем
class MyController
{
public function indexAction()
{
$this->getRepository('MyCoreBundle:ClassA')->myMethod();
// [...]
}
}
Результат:
classA 566208
INFO 16286 found
Но в другой части кода
class MyService
{
private function myServiceMethod()
{
$this->doctrine->getManager()
->getRepository('MyCoreBundle:ClassA')->myMethod();
}
}
Результат:
classA 566208
ERROR 16286 Not found
Что может вызвать это? Я немного смущен и не знаю, надежна ли моя Доктрина.
Моя конфигурация "php": "> = 5.5", "symfony/symfony": "2.8. *", "Doctrine/orm": "~ 2.5",
Я сделал MySQLcheck, все выглядит нормально.
EDIT/TL;DR:
Этот код...
echo "<pre>";
echo "NORMAL\n";
$classC = $this->doctrine->getManager()->getRepository('MyCoreBundle:ClassC')->find(7);
$classDs = $classC->getClassDs();
$found = false;
foreach ($classDs as $classD) {
if (16286 == $classD->getId()) {
$found = true;
echo "INFO 16286 found\n";
}
}
if (false == $found) echo "ERROR 16286 Not found\n";
echo "INVERSED\n";
$classDs = $this->doctrine->getManager()->getRepository('MyCoreBundle:ClassD')->findBy(array("classC" => 7));
$found = false;
foreach ($classDs as $classD) {
if (16286 == $classD->getId()) {
$found = true;
echo "INFO 16286 found\n";
}
}
if (false == $found) echo "ERROR 16286 Not found\n";
echo "</pre>";
... дает...
NORMAL
ERROR 16286 Not found
INVERSED
INFO 16286 found
Проблема заключалась в том, что запросы были выполнены до вызова сервиса myMethod, а Doctrine поместили в кеш некоторые подчасти этих запросов.
Решение заключалось в том, чтобы попросить Entity Manager очистить кеш.
$this->doctrine->getManager()->clear();
$this->doctrine->getManager()
->getRepository('MyCoreBundle:ClassA')->myMethod();
Если вы только запрашиваете этот идентификатор, вам не нужно и не следует перебирать каждую запись таблицы, если она не нужна. Что-то вроде этого:
$this->doctrine->getManager->getRepository->('MyCoreBundle:ClassA')->find(16286)
намного эффективнее. И вы можете выбрать entityManager изнутри репозитория и получить репозиторий для класса C и запросить его с идентификатором напрямую.
Вы уверены, что ничто не меняет отношения между двумя вызовами метода?
Я использую Доктрину в течение некоторого времени, а также в производстве, но у меня не было такой проблемы.