想象一下以下情况。你有书:
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以获取此特定查询(不是通过配置全局)?
您可以简单地将书籍和作者之间的关联标记为EAGER
(而不是隐式默认值
LAZY
),Doctrine 将始终预先加载该特定关联。这可以通过添加来完成:
fetch=EAGER
至地图协会。在运行时执行此操作的一种潜在方法是创建一个“映射超类”。超类将定义您的关系和关联的其他部分(而不是您试图调整的关系)。
然后,要在运行时实际使用该类,您可以创建另外两个具体实现:LazyBook
EagerBook
。根据运行时的场景,您将使用这些具体实现实体中的一个或另一个来构建您的关联。
当然,
LazyBook
会将您的 Book
->
Author
关联定义为
LAZY
关联(显式或隐式),并且
EagerBook
会将其定义为
EAGER
。
这并不是您定义的“真正”动态,但它允许您以编程方式确定在任何给定时间使用哪个关联,同时还可以自我记录它可以是其中之一。
这里要理解的一件非常重要的事情是,Doctrine 使用 Data Mapper 模式
而不是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 实体”,而不是数据库列/表。