Doctrine:如何以编程方式启用预加载?

问题描述 投票:0回答:2

想象一下以下情况。你有书:

Book(bookId, authorId, title)

和作者:

Author(authorId, name)

每本书都有一个作者(为了简单起见)。

默认情况下,所有关联都配置为 lazy 模式。因此,如果我有这样的场景,当我第一次加载所有书籍、迭代集合并获取每本书的作者时,我将对数据库执行大量查询。

$books = $this->getDoctrine()
        ->getRepository('AppBundle:Book')
        ->findAll();

foreach($books as $b) {
    echo $b->getAuthor()->getName();
}

我可以以编程方式要求 Doctrine 急切地加载authors以获取此特定查询(不是通过配置全局)?

相关: 在原则 2 中,Fetch 模式(Eager/Lazy 等)可以在运行时更改吗?

相关:http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/tutorials/getting-started.html#list-of-bugs

php orm doctrine-orm relationship symfony
2个回答
3
投票

您可以简单地将书籍和作者之间的关联标记为EAGER

(而不是隐式默认值
LAZY
),Doctrine 将始终预先加载该特定关联。

这可以通过添加来完成:

fetch=EAGER
至地图协会。

在运行时执行此操作的一种潜在方法是创建一个“映射超类”。超类将定义您的关系和关联的其他部分(而不是您试图调整的关系)。

然后,要在运行时实际使用该类,您可以创建另外两个具体实现:LazyBook

EagerBook

。根据运行时的场景,您将使用这些具体实现实体中的一个或另一个来构建您的关联。
当然, 
LazyBook

会将您的

Book

 -> 
Author
 关联定义为 
LAZY
 关联(显式或隐式),并且 
EagerBook
 会将其定义为 
EAGER
这并不是您定义的“真正”动态,但它允许您以编程方式确定在任何给定时间使用哪个关联,同时还可以自我记录它可以是其中之一。

这里要理解的一件非常重要的事情是,Doctrine 使用 Data Mapper 模式

而不是

-2
投票
(例如,您可以在 Yii 框架中找到它):

Doctrine 2 是 PHP 5.4+ 的对象关系映射器 (ORM) 为 PHP 对象提供透明的持久性。 它使用数据 映射器模式位于核心,旨在完全分离您的 来自关系数据库中持久性的域/业务逻辑 管理系统。

Doctrine 对程序员的好处是能够专注于 面向对象的业务逻辑,只关心持久性 次要问题。这并不意味着持久性会被淡化 然而,我们相信原则 2 存在相当大的 持久性和实体对面向对象编程的好处 保持分开。

http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/tutorials/getting-started.html#what-is-doctrine

这本质上意味着,实体类

对它们如何持久化到数据库一无所知。尽管它们可以有注释类型注释,但这些只是 ORM 处理的元数据的一种形式。

这意味着您可以执行与 ActiveRecord 相同的操作,但现在只是在另一个地方完成。我们来看看区别:

在基于 ActiveRecord 的 ORM 中(如 Yii):

$books = Book::model()->with('author')->findAll();

在基于 DataMapper 的 ORM 中(如 Symfony/Doctrine):

$books = $this->getDoctrine()->createQueryBuilder()
  ->select(['b', 'a'])
  ->from('AppBundle:Book', 'b')
  ->join('b.author', a')
  ->addSelect('a')
  ->getQuery()
  ->getResult();

稍后的小评论。您在那里构建的查询不是“SQL 查询”,而是“DQL 查询”(Doctrine 使用的对象查询语言)。 所以这里的

join/addSelect
很像前一个查询中的
with

,只是告诉ORM引擎你想在同一个查询中加载author。特定的关系元数据(例如两个基础表的列名称)仍然在实体元数据级别定义。 语法(select、from、join)类似于 SQL

故意

,但您不应该被它迷惑。在这里,构建查询时,您操作的是“ORM 实体”,而不是数据库列/表。

© www.soinside.com 2019 - 2024. All rights reserved.