Doctrine ORM Проблема ассоциации наследования одной таблицы (всегда нетерпеливая загрузка вопреки документации) - PullRequest
3 голосов
/ 17 июня 2011

У меня проблема с наследованием одной таблицы, и я не уверен, правильно ли я интерпретирую документацию.

Первый: Я не скопировал сопоставления моего кода / сущностимногословно (или даже используя правильный синтаксис) здесь, так как я думаю, что проблема может быть лучше изложена абстрактно.Если это неприемлемо, скажите так, и я добавлю полный код - но он ДОЛГО и я думаю, что на мой вопрос можно ответить без него.

Если это поможет, я могу нарисовать диаграмму ER дляпопробуйте и сообщите, что я пытаюсь сделать.Если вы читаете следующее и думаете «эй, это должно сработать» - скажите мне, и я загружу реальный код

Второй: Я нигде не использую ленивую загрузку.Прежде чем получить доступ к своим сущностям, я проверяю, что загружаю каждую связанную сущность, к которой я собираюсь получить доступ, написав DQL заранее - поэтому следующая проблема довольно терминальна для моего приложения)

Настройка:

У меня есть несколько сущностей - они составляют ядро ​​моего приложения.

// @entity AnimalTrainingSchool
//   oneToMany: trainingDepartment
     fields: [name / location / year founded]
// @entity trainingDepartment
     oneToMany: animalTrainer
     oneToOne: building
     fields: [capacity]
// @entity animalTrainer
     fields: [name / age / qualification]

Я получаю к ним доступ часто и в разных контекстах - но я обычно повторяю уровни и свойства доступа и отношения для этих объектов.

foreach ($animalTrainingSchool as $school){
    echo $school->getName() . ' at ' . $school->getLocation();
    echo 'These are the training departments for this school:';
    foreach ($school->getTrainingDepartments as $trainingDepartment){
        echo $trainingDepartment->getAnimalTypeTrained() . ' are trained in this department';
    }
}

Я удостоверяюсь, что все онизагрузил сразу, сформировав мой DQL и выполнив его - чтобы ограничить количество SQL-запросов (до одного).Все это прекрасно работает (довольно стандартные вещи).

DQL Example : "SELECT ats, td, at FROM AnimalTrainingSchool ats JOIN AnimalTrainingSchool.trainingDepartments td JOIN td.animalTrainer at";

Это настраивает мою коллекцию и означает, что я могу пройти по ней без необходимости выполнять дополнительные запросы

Проблема:

Я сопоставил другие объекты в другом месте моего приложения - очень похоже на это (ПРИМЕЧАНИЕ: мой общий вопрос очень похож на приведенный ниже вопрос с одним ОСНОВНЫМ отличием (см. Ниже)

Доктрина 2 Отображение наследования с ассоциацией

// NB: new awards are issued each time they are awarded - so it is meant to be a oneToOne relationships - the awards are unique
// @entity award
     {id information / table information / discriminator map / inheritance type (SINGLE_TABLE)}
     fields: [medalMaterial / award_serial_number]
//departmentAward extends award
    oneToOne: trainingDepartment
//trainerAward extends award
    oneToOne: animalTrainer

Затем я установил двустороннюю связь, изменив свои начальные сущности

// @entity trainingDepartment
     oneToMany: animalTrainer
     oneToOne: building
     oneToOne: departmentAward
     fields: [capacity]
// @entity animalTrainer
     fields: [name / age / qualification]
     oneToOne: trainerAward

Что происходит

Теперь, когда я получаю доступ к своим исходным сущностям точно так же, как и выше - они автоматически (охотно) загружают ассоциированную сущность для своих наград, хотя я им не говорю. Это особенно плохо, когда я повторяю, хотяцелая куча trainingDepartments / AnimalTrainers и Doctrine выполняет оператор SQL для КАЖДОГО объекта.

Для 20 отделов с10 тренеров в каждом - это 200 дополнительных запросов.

//Given the exact same DQL and foreach loop as above (note that at no stage am I accessing awards) - I get a ton of extra queries that look like this

"SELECT award.property1, award.property2, award.property3 FROM awardTable LEFT JOIN trainingDepartmentTable ON award.awardee_id = trainingDepartmentTable.id and award.discriminatorColumn IN ('departmentAward')";
// or...
"SELECT award.property1, award.property2, award.property3 FROM awardTable LEFT JOIN animalTrainerTable ON award.awardee_id = animalTrainerTable.id and award.discriminatorColumn IN ('trainerAward')";

Ничего из того, что генерируется, неверно - просто, прочитав следующий вопрос, мне кажется, что я настроил это какдокументация описывает (и наоборот @Matthieu;а именно - если я связал мои начальные 3 энтита с сущностями уровня LOWEST, а не с базовым классом «вознаграждение», тогда они ДОЛЖНЫ иметь возможность использовать прокси вместо попыток активной загрузки сущностей.

StackoverflowВопрос, который задает противоположное тому, что я описываю

Доктрина 2 Отображение наследования с ассоциацией

Соответствующая документация доктрины

http://www.doctrine -project.org / docs / orm / 2.0 / en / reference / наследование-mapping.html # Performance-Impact

Существует общая производительностьРассмотрение с наследованием одной таблицы: если вы используете объект STI в качестве объекта «многие к одному» или «один к одному», вы никогда не должны использовать один из классов на верхних уровнях иерархии наследования как «targetEntity», только те, которыене имеет подклассов.В противном случае Doctrine НЕ МОЖЕТ создавать прокси-экземпляры этой сущности и ВСЕГДА будет загружать сущность с нетерпением.

Мне кажется, что независимо от того, присоединяетесь ли вы к сущности базового уровня или нетили объект подкласса - Doctrine будет охотно загружать ассоциации и не будет пытаться использовать прокси.

Опять же: я могу опубликовать реальный код - но учитывая длину вопроса, я чувствовал, что лучше не делать этого.Любой вклад приветствуется.

1 Ответ

4 голосов
/ 19 июня 2011

Обратная сторона отношения oneToOne не может быть загружена с отложенной загрузкой. Для поддержки отложенной загрузки Doctrine необходимо создать прокси-объект, но прокси-объектам необходимо иметь связанный с ними идентификатор. В случае отношений oneToOne идентификатор доступен только на стороне владельца. Таким образом, обратные отношения должны быть загружены с нетерпением.

Вы должны попытаться получить присоединение к этим ассоциациям, если это возможно. Версия 2.1 автоматически принудительно выбирает соединения для обратных отношений oneToOne.

...