教条:QueryBuilder与createQuery之间的区别?

74

在Doctrine中,你可以通过两种方式创建DQL查询:

EntityManager::createQuery:

$query = $em->createQuery('SELECT u FROM MyProject\Model\User u WHERE u.id = ?1');

查询生成器:

$qb->add('select', 'u')
   ->add('from', 'User u')
   ->add('where', 'u.id = ?1')
   ->add('orderBy', 'u.name ASC');

我想知道它们之间的区别,以及应该使用哪个?

5个回答

70
  1. DQL更易于阅读,因为它与SQL非常相似。如果您不需要根据一组参数更改查询,则这可能是最佳选择。

  2. Query Builder是一个api,用于构建查询,因此如果您需要动态构建查询(例如迭代一组参数或过滤器),则更容易使用。您不需要执行任何字符串操作来构建查询,例如join、split或其他操作。


1
但是在第一种情况下,解析DQL字符串不会有额外的开销吗?或者生成器也会产生相同的DQL字符串作为结果吗? - Alexey Kosov
4
是的,QueryBuilder 会为您创建 DQL 字符串。之后,DQL 仍然会被解析。 - Dennis
如果我理解正确的话,基本上你不应该用它来进行删除或更新操作?因为它不会更新Doctrine缓存,也不会调用事件等。在发出事件方面,DQL和查询构建器有什么区别?它们是一样的吗? - Toskan

34

查询构建器只是一个接口,用于创建查询... 它应该更加舒适易用,不仅具有 add()方法,还有像 where(),andWhere(),from()等方法。但最终,它只是像在 createQuery()方法中使用的那样组合查询。

查询构建器更高级使用的示例:

$em->createQueryBuilder()
            ->from('Project\Entities\Item', 'i')
            ->select("i, e")
            ->join("i.entity", 'e')
            ->where("i.lang = :lang AND e.album = :album")
            ->setParameter('lang', $lang)
            ->setParameter('album', $album);

1
你可以添加 ->setParameters(array('x' => 'y', 'z' => 'w', ...))。 - Herr Nentu'

17

它们有不同的目的:

  • 当您知道完整查询时,DQL 更易于使用。
  • 当您必须基于某些条件、循环等构建查询时,查询生成器更加智能。

4
主要的区别在于调用方法时的开销。你的第一个代码示例(createQuery)仅仅为了简单,调用了一次方法,而queryBuilder则调用了4次。最终它们都会变成一个需要被执行的字符串,在第一个示例中你直接给出了这个字符串,而在另一个示例中你通过多个链接的方法调用来构建它。
如果你正在寻找使用其中一个的理由,那就是一个风格问题,看起来哪个更容易读懂。对我而言,大多数情况下我喜欢使用queryBuilder,因为它为查询提供了明确定义的部分。此外,在过去,当你需要添加条件逻辑时,使用它会更加容易。

一个小观察 - 我会说,与 SQL 相关的任何数量的 PHP 函数调用所花费的时间几乎总是比与数据库交谈、等待和提取实际结果所花费的时间更不重要(更不用说在 ORM 的情况下还需要将它们转化为对象)。 - userfuser

2
使用查询构建器进行单元测试可能会更容易。假设您有一个存储库,根据复杂的条件列表查询某些数据,并且您想确保如果将特定条件传递到存储库,则会将其他条件添加到查询中。在使用DQL的情况下,您有两个选项:
1)使用固定装置并测试与DB的实际交互。我觉得有些麻烦和不太适合单元测试。
2)检查生成的DQL代码。这可能会使您的测试过于脆弱。
使用QueryBuilder,您可以用模拟替换它,并验证是否调用了具有所需参数的“andWhere”方法。当然,如果您的查询很简单且不依赖于任何参数,则不适用此类考虑。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接