2016-04-06 2 views
1

Я читал много о доктрине в последнее время, и я видел общее предложение избежать двунаправленных ассоциаций «один-к-одному». This page (с июня 2015 года) гласит:Ленивая загрузка ассоциаций «один-к-одному» доктрины

... you should avoid bidirectional one-to-one associations in Doctrine. 
    The inverse side of a one-to-one association cannot be lazy loaded. 

Я предполагаю, что не может быть ленивым загружен означает что-то вроде должен быть готов загруженным.

страница также называется «Doctrine Performance Ловушки», так это выглядит страшно :)

Поскольку manual on one-to-one не упомянул об этом, я решил проверить и посмотреть на себя. Я нашел пару классов в нашем тестовом приложении, которые уже используют один-к-одному ассоциации, так что это было легко:

class Recipe 
{ 
    /** 
    * @ORM\OneToOne(targetEntity="Image") 
    * @ORM\JoinColumn(name="image_id", unique=true, referencedColumnName="id") 
    */ 
    private $image; 
} 

class Image 
{ 
    /** 
    * @ORM\OneToOne(targetEntity="Recipe") 
    * @ORM\JoinColumn(name="recipe_id", referencedColumnName="id") 
    */ 
    private $recipe; 
} 

Далее, я стараюсь, чтобы выбрать изображение в моем контроллере:

$image = $em->getRepository('AppBundle:Image')->find(658); 

В профилировщике Symfony я вижу один sql-запрос без соединений. В данном демпинговом изображении под рецептом, я вижу:

+__isInitialized__: false 

Что будет означать, что рецепт объект был ленивым загружен?

То же самое происходит при загрузке Рецепта: Изображение загружается ленивым.

Добавление inversedBy к любому из объектов, похоже, не имеет значения.

Кажется, что либо статья, которую я читала, была неправильной, или что-то изменилось в Доктрине с тех пор, или я не понимаю ленивой загрузки.

Вопросы:

  • Может последние версии доктрины ленивых нагрузки двунаправленного один-к-онов?
  • Почему двунаправленные ассоциации «один-к-одному», которые часто считаются вредными для производительности?

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

Спасибо!

ответ

1

Я думаю, что вы делаете некоторую путаницу между ленивой и нетерпеливой нагрузкой.

Ленивой Загрузка не загружают данные, связанные с джойна заявления: когда вы пытаетесь получить доступ к дочернему объекту (от родителей), вы на самом деле сделать вызов прокси-объект, который будет запускать избранное заявление с правильные условия. Следует избегать ленивой загрузки, если вы хотите получить данные, которые будут доступны для вас.

Eager Loading загружает связанные данные с помощью инструкции объединения в одном запросе. Это поможет вам решить накладные расходы «n + 1».

Предположим, у вас есть несколько категорий и подкатегорий, разделенных в одной таблице (я знаю, это странно для подхода к нормализации базы данных, но поможет нам получить оценку): вы собираетесь отображать меню со категориями и подкатегориями , С помощью Eager Loading для каждой категории вы создадите оператор выбора для получения данных подкатегории (т. Е. Имя, которое вы укажете в своем меню).

Что касается двунаправленного отношения «один-к-одному», то причина, по которой его загрузка двунаправленно вызывает накладные расходы, довольно проста: предположим, что A имеет взаимно однозначное отношение с B. Когда вы загружаете A, вы собираетесь сделайте прокси-объект, который указывает прямо на B. Если вы установите двунаправленную связь, ваш прокси-объект B будет содержать (неиспользуемый) прокси-объект тоже.

Надеется, что это помогает (и что я не сделал ни одной ошибки на самом деле) (:

+0

Я понял фразу ** Обратная сторона взаимно однозначной ассоциации не может быть ленивой загруженной ** таким образом, что ** Она должна быть загружена, потому что она не может быть ленивой загружена ** :) Вот почему я ожидал присоединения. – Karolis

0

Вашего отображения для двунаправленной ассоциации один-к-одному не правильно Обычно у вас есть @JoinColumn только на одном конце. ассоциация, а не на обоих концах:

<?php 
class Recipe 
{ 
    /** 
    * @ORM\OneToOne(targetEntity="Image", mappedBy="recipe") 
    */ 
    private $image; 
} 

class Image 
{ 
    /** 
    * @ORM\OneToOne(targetEntity="Recipe", inversedBy="image") 
    * @ORM\JoinColumn(name="recipe_id", referencedColumnName="id") 
    */ 
    private $recipe; 
} 

см http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-one-bidirectional

Если настроить отображение, как это и загрузите Recipe вы увидите ожидаемый JOIN с Image таблица.

Смежные вопросы