Eager loading of related entity in Symfony 2

2019-02-16 11:23发布

There are three entities: Customer, Messages, Attachments.

The relationship between these entities is straight forward: A customer can have many messages and a message can have many attachments. Both relations are "one-to-many".

I told doctrine to be lazy when loading the messages for the Customer entity. So $customer->getMessages() results in an additional SQL statement. That's fine.

But I also defined an "EAGER" loading for the attachments for the Message entity.

Now I would have expected that the messages I get by calling $customer->getMessages() are already loaded with all their attachments. But $message->getAttachments() still causes one SQL statement per message.

Is this behavior expected?

Just for reference, excepts from my classes:

Customer.php

class Customer
{
    /**
     * @ORM\OneToMany(targetEntity="Message", mappedBy="customer")
     * @ORM\OrderBy({"createdOn" = "DESC"})
     */
    private $messages;

Message.php

class Message
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="Customer", inversedBy="messages")
     * @ORM\JoinColumn(name="customer_id", referencedColumnName="id")
     **/
    private $customer;
    /**
     * @ORM\OneToMany(targetEntity="Attachment", mappedBy="message", fetch="EAGER")
     **/
    private $attachments;

Attachment.php:

class Attachment
{

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="Message", inversedBy="attachments")
     * @ORM\JoinColumn(name="message_id", referencedColumnName="id")
     **/
    private $message;

2条回答
仙女界的扛把子
2楼-- · 2019-02-16 11:31

It sounds like expected behavior to me. The doctrine documentation seems to imply that eager fetching is only one level deep.

According to the docs:

Whenever you query for an entity that has persistent associations and these associations are mapped as EAGER, they will automatically be loaded together with the entity being queried and is thus immediately available to your application.

http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-objects.html#by-eager-loading

The entity being queried in your case is customer and customer has eager on messages so messages are populated. Messages, however are not the object being queried, so attachments do not get loaded.

查看更多
淡お忘
3楼-- · 2019-02-16 11:50

the correct code example might be like the following:

NOTE: fetch message with lazy loading, i.e. get messages with additional query proactively; as long as the messages are fetched from database, the corresponding attachments referenced to each message will be loaded automatically.

Customer

class Customer
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\OneToMany(targetEntity="Message", mappedBy="customer", fetch="LAZY")
     * @ORM\OrderBy({"createdOn" = "DESC"})
     */
    private $messages;

Message

class Message
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="Customer", inversedBy="messages")
     * @ORM\JoinColumn(name="customer_id", referencedColumnName="id")
     */
    private $customer;

    /**
     * @ORM\OneToMany(targetEntity="Attchment", mappedBy="message", fetch="EAGER")
     */
    private $attachments;

Attachment

class Attachment
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToONe(targetEntity="Message", inversedBy="attachments")
     * @ORM\JoinColumn(name="message_id", referencedColumnName="id")
     */
    private $message;
查看更多
登录 后发表回答