Doctrine2一对一关系自动加载查询

And*_*ird 33 doctrine-orm

我有一个看起来像这样的查询:

我的用户实体具有一对一的关系,如下所示:

/**
 * @var UserProfile
 *
 * @ORM\OneToOne(targetEntity="UserProfile",mappedBy="user")
 */
private $userProfile;
Run Code Online (Sandbox Code Playgroud)

每当我进行查询以选择多个用户对象时,它会为每个用户创建一个额外的select语句来查询UserProfile数据,即使我没有通过get方法访问它.我并不总是需要UserProfile数据,我当然不希望每次显示用户列表时都加载这些数据.

知道为什么这些查询在运行时执行?

Let*_*eto 23

以下是解决方案详细解释:

https://groups.google.com/forum/#!topic/doctrine-user/fkIaKxifDqc

映射中的"fetch"是一个提示,也就是说,如果Doctrine可以这样做,但如果它不可能,显然它不会.从技术上讲,代表延迟加载并不总是可行的.不可能的情况是:

1)从反向到拥有方一对一(仅出现在双向一对一关联中).上述条件a)无法满足.2)与层次结构的一对一/多对一关联,目标类具有子类(不是类层次结构中的叶子).上述前提条件b)无法满足.

在这些情况下,代理在技术上是不可能的.

您可以选择避免这个n + 1问题:

1)通过DQL获取连接:"从客户加入c.cart ca中选择c,ca".然而,单个查询但加入,加入一对一关联相对便宜.

2)强制部分物体.没有其他查询但也没有延迟加载:$ query-> setHint(Query :: HINT_FORCE_PARTIAL_LOAD,true)

3)如果替代结果格式(即getArrayResult())足以用于用例,这些也避免了这个问题.

Benjamin有一些关于自动批处理这些负载以避免n + 1查询的想法,但这并没有改变代理并不总是可行的事实.


小智 17

我花了很多时间寻找解决方案.对我来说,没有一个选项足够令人满意,但也许我可以通过这个变通方法列表节省一些时间:

1)改变拥有方和反方http://developer.happyr.com/choose-owning-side-in-onetoone-relation - 我不认为每次都是从数据库设计的角度来看是正确的.

2)在类似的功能find,findAll等等,在OneToOne逆侧被自动接合(它总是喜欢取EAGER).但是在DQL中,它不像fetch EAGER那样工作,并且需要额外的查询.可能的解决方案是每次与反向实体连接

3)如果替代结果格式(即getArrayResult())足以满足某些用例,那么也可以避免这个问题.

4)改变反面是OneToMany - 看起来不对,也许可能是一个临时的解决方法.

5)强制部分对象.没有其他查询,也没有延迟加载:$query->setHint (Query::HINT_FORCE_PARTIAL_LOAD, true)- 接缝给我唯一可能的解决方案,但不是没有价格:部分对象有点冒险,因为您的实体行为不正常.例如,如果您未在->select()用户指定的所有关联中指定错误,因为您的对象将不会满,则所有未明确选择的关联都将为null

6)不映射反向双向OneToOne关联,并使用显式服务或更活跃的记录方法 - https://github.com/doctrine/doctrine2/pull/970#issuecomment-38383961 - 看起来像Doctrine关闭问题


apf*_*box 11

看来这是Doctrine中的一个公开问题,另见

4.7.1.为什么每次获取具有一对一关系的实体时都会执行额外的SQL查询?

如果Doctrine检测到您正在获取反向一对一关联,则必须执行另一个查询来加载此对象,因为它无法知道是否没有此类对象(设置为null)或者是否应设置代理和该代理具有哪个ID.为了解决这个问题,目前必须执行查询以找出该信息.

资源