【问题标题】:Expand multiple collections of an entity in Doctrine在 Doctrine 中展开一个实体的多个集合
【发布时间】:2017-12-02 07:02:01
【问题描述】:

我正在编写一个 Symfony 应用程序,并且遇到了 Doctrine 实体急切加载的问题。 我不确定是否可以在同一个实体实例上加载多个一对多集合,同时保持良好的性能。

互联网上有很多例子,人们加载一个实体及其关系之一。 例如:

 $user = $em->createQuery('
     select a, au
     from OctiviTestBundle:Article a
     left join a.authorList au
     where a.id = ?1')
  ->setParameter(1, $id)
  ->getOneOrNullResult();

但是如果我也想加载文章cmets,下面的请求检索到的结果太多(nb authors * nb cmets) => 组合爆炸

 $user = $em->createQuery('
     select a, au
     from OctiviTestBundle:Article a
     left join a.authorList au
     left join a.commentList c
     where a.id = ?1')
  ->setParameter(1, $id)
  ->getOneOrNullResult();

事实上,一旦从数据库中加载了一个对象,我就没有办法重用它。我不知道如何进行第二次查询以稍后加载更多部分。 例如:

  $user = $em->createQuery('
     select a, au
     from OctiviTestBundle:Article a
     left join a.authorList au
     where a.id = ?1')
  ->setParameter(1, $id)
  ->getOneOrNullResult();
  $em->LoadRelation($user, 'commentList');
  $em->LoadRelation($user, 'commentList.author')
  $em->LoadRelation($user, 'commentList.author.school');
  ... load any relation I want, while keeping only one root object.

我希望能够只有主实体实例变量,急切加载它的 2 个关系,然后遍历层次结构。 我知道我可以在不同的 php 变量中加载这两个列表,但我只想将“$user”变量传递给视图模板。

您对如何解决此问题有想法吗? 谢谢

我找到的唯一(棘手的)解决方案是在这个网站上:https://tideways.io/profiler/blog/5-doctrine-orm-performance-traps-you-should-avoid

1)加载相关实体
$companies = array_map(function($employee) {
    return $employee->getCompany();
}, $employees);
$repository = $entityManager->getRepository('Acme\Company');
$repository->findBy(['id' => $companies]);
2) 不要使用结果(删除 $companies 变量),但是现在 Doctrine 已经在缓存中获得了结果,所以当我执行 $employee->getCompany()->getName() 时,它不应该生成新的查询。

=> 不起作用:Doctrine 不会将结果放入缓存中以供以后重用。

【问题讨论】:

    标签: php symfony doctrine-orm entity-relationship


    【解决方案1】:

    如果无论您输入什么where'sands,结果总是很大,并且如果您不打算对结果进行任何写入操作,则应该将它们作为数组而不是作为默认对象。

    生成的数组在 twig 中的使用仍然完全相同,但是因为您不再需要对对象进行水合,您的内存节省将是巨大的。

    【讨论】:

    • 结果应该是 20 个作者 + 20 cmets(40 行),而不是 20 个作者 * 20 cmets(400 行)。没错,使用数组,我可以在需要时加载日期并引用单个用户数组中的所有内容。
    • 不过,我也有使用用户对象的业务逻辑,所以我更喜欢水合对象
    • 如果它只有 40 行甚至 400 行,您应该不会真正看到任何真正的性能问题。在我的脑海里,我在想1000。值得您打印 Sql ->getSQL() 并在 MySQL 中手动运行查询,以查看是 Sql 还是对象水合杀死了您。也许你的索引有点偏离。
    • 在真正的应用程序中,它是 3600 行而不是 120 行。有一个 where 子句:I qwuery for all data about a specific article
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-11
    • 1970-01-01
    相关资源
    最近更新 更多