Доктрина запускает слишком много запросов с помощью innerJoin

Учитывая этот код, Doctrine запускает столько запросов, сколько строк у меня в table2

$qb = $this->getModelManager()->createQuery($er->getClassName(), 't1')->getQueryBuilder();

$qb->select('t1, t2, t3')
   ->innerJoin('table1.table2', 't2');
   ->innerJoin('table2.table3', 't3')
   ->where('t3.id = :foo')
   ->setParameter('foo', $foo);

каждый запрос похож на этот:

SELECT t0.id AS id_1,
       t0.name AS name_2, 
       t0.slug AS slug_3,
       t0.description AS description_4, 
       t0.visible AS visible_5 
FROM table2 t0 
WHERE t0.id = ?

и это сущности:

ТАБЛИЦА 1: основная сущность, ведьма, связана с таблицей 2 с помощью manyToOne, если я сделаю innerJoin с таблицей 2, Doctrine будет действовать, как ожидалось (1 запрос)

/**
 * @ORM\Entity(repositoryClass = "Table1Repo")
 * @ORM\Table(name = "table1")
 */
class table1 extends BaseTable1 implements table1Interface
{
    /**
     * @ORM\Id
     * @ORM\Column(type = "integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\Column(type = "string", length=255)
     * @Gedmo\Versioned
     */
    protected $name;

    /**
     * @ORM\ManyToOne(targetEntity = "table2", inversedBy = "tables1")
     * @ORM\JoinColumn(name = "table2_id", referencedColumnName = "id", onDelete = "CASCADE")
     */
     protected $table2;
}

ТАБЛИЦА 2, связанная с первой таблицей от OneToMany и с таблицей 3 от ManyToMany.

/**
 * @ORM\Entity(repositoryClass = "table2Repository")
 * @ORM\Table(name = "table2")
 */
class table2 extends Basetable2
{
    /**
     * @ORM\Id
     * @ORM\Column(type = "integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\ManyToMany(targetEntity = "table3", inversedBy = "table2s")
     * @ORM\JoinTable(name = "table3_table2")
     */
    protected $table3;

    /**
     * @ORM\OneToMany(targetEntity = "table1", mappedBy = "table2")
     * @Accessor(getter = "getTables1")
     */
    protected $tables1;
}

ТАБЛИЦА 3: они связаны с таблицей 2 отношением ManyToMany. Когда я делаю innerJoin с таблицей 2, Doctrine по-прежнему действует так, как ожидалось, выполняя только один запрос

/**
 * @ORM\Entity(repositoryClass = "table3Repo")
 * @ORM\Table(name = "table3")
 * @Gedmo\Loggable
 */
class table3 extends Basetable3
{
    /**
     * @ORM\Id 
     * @ORM\Column(type = "integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\ManyToMany(targetEntity = "table2", mappedBy = "tables3")
     * @ORM\JoinTable(name = "table3_table2")
     */
    protected $tables2;
}

Итак, когда я добавляю оба innerJoins в конструктор запросов, Doctrine выполняет только один запрос, но когда я добавляю предложение WHERE, когда Doctrine выполняет 279 запросов, по одному на строку в table2, ведьма связана с table1 через oneToMany и с table3 пользователя ManyToMany.

Другой важный момент заключается в том, что построитель запросов выполняется под опцией поля query_builder SonataAdmin.

Я не могу понять, почему у меня такое поведение, есть подсказка?

Это довольно стандартное поведение любого ORM. Прочтите, как работать с Коллекции в Doctrine.

emix 03.10.2018 12:48

Ну, я понимаю, что гидратация manyToMany включает в себя запрос к средней таблице между двумя объектами, но это не то, что делает ORM, она извлекает все данные из одной из таблиц и извлекает столько объектов, сколько строк в таблице, и вот чего я не понимаю. Фактически, запросы выполняются, когда я обрабатываю данные, которые уже получены с помощью внутренних соединений.

Krleza 03.10.2018 13:38

Запросы являются результатом не самого запроса, а обхода графа объектов в представлении.

emix 03.10.2018 13:53
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
3
57
1

Ответы 1

Когда вы запускаете запрос, у вас всегда должен быть корневой объект, который присоединяется к другим. В вашем случае это table1. После выборки, на основе метаданных запроса и объекта, Doctrine попытается создать объект для каждого экземпляра root, но если не указано иное на этом остановится. Фактически, для каждого подобъекта (например, table2) он будет создавать фиктивные «прокси-объекты», которые едва ли являются поверхностными представлениями и должны быть разрешены из БД всякий раз, когда пытается их разыменовать. Процесс преобразования результатов БД в объекты известен как гидратация объекта.

Чтобы выполнить гидратацию подобъектов, вам нужно также «выбрать» подобъект:

$qb->select('t1', 't2', 't3')
    ->innerJoin('t1.table2', 't2');
    ->innerJoin('t2.table3', 't3')
    ->where('t3.id = :foo')
    ->setParameter('foo', $foo);

Обратите внимание, чтобы не сходить с ума, получая все, так как это занимает больше времени и потребляет значительно больше оперативной памяти. Настраивайте свой запрос до тех пор, пока не достигнете желаемого (логики и производительности).

Надеюсь это поможет...

Уже пробовал, но все равно схожу с ума от запросов, все равно спасибо.

Krleza 03.10.2018 12:05

Хм, если я не ошибаюсь, вы не можете присоединиться по «table1.id», так как это не относительный атрибут. Я скорректировал ответ, чтобы отразить структуру сущностей ... Можете попробовать?

Jovan Perovic 03.10.2018 13:34

сделал, и ничего, обновил вопрос. еще раз спасибо.

Krleza 03.10.2018 13:50

Это кажется довольно странным. По общему мнению, это должно работать. Есть ли еще какая-нибудь информация по этой проблеме, которой вы могли бы поделиться?

Jovan Perovic 04.10.2018 01:16

Другие вопросы по теме