symfony - Doctrine2 - 没有关系的子查询连接

标签 symfony doctrine-orm dql query-builder

好的,问题来了。

我有一个名为 HelpDocuments 的实体和一个名为 LogEntry 的实体。

HelpDocuments 可以被用户关闭。发生这种情况时,我会创建一个具有以下属性的 LogEntry:

  • 事件 - 例如:helpDocument.dismiss
  • entity_id - 例如:11
  • entityDiscriminator - 例如:HelpDocument

HelpDocument 和 LogEntry 之间没有创建任何关系,因为我正在实现自己的鉴别器逻辑。

所以我想要实现的是查询所有尚未被关闭的 HelpDocuments。我可以用 sql 做到这一点,左外部子查询连接如下:

SELECT HelpDocument.*, temp.*
FROM HelpDocument
LEFT OUTER JOIN(
    SELECT LogEntry.entity_id
    FROM LogEntry
    WHERE LogEntry.entityDiscriminator = 'HelpDocument'
    AND LogEntry.event = 'helpDocument.dismiss'
    AND LogEntry.entity_id = 11
) as temp ON HelpDocument.id = temp.entity_id
WHERE temp.entity_id IS NULL;

我的问题是如何在没有定义关系的情况下将其转换为 DQL?


更新的解决方案:

因此解决方案是不使用 LEFT OUTER JOIN,因为它们在 Doctrine2 中不存在/没有意义。最后我不得不做一个子查询连接:

/**
 * Filter by User Dismissed
 *
 * @param $qb
 * @param $route
 * @return mixed
 */
public function filterQueryByUserDismissed(QueryBuilder $qb, $args)
{
    $args = array_merge(array(
        "user" => null,
        "dismissed" => false
    ), $args);

    /** @var $dismissedQB QueryBuilder */
    $dismissedQB = $this->_em->createQueryBuilder();

    /*
    This line is important. We select an alternative attribute rather than
    letting Doctrine select le.id
    */
    $dismissedQB->select('le.entityId')
                ->from('\Mlf\AppBundle\Entity\UserEntityEventLog', 'le')
                ->where('le.entityDiscriminator = :entityDiscriminator')
                ->andWhere('le.event = :event')
                ->andWhere('le.user = :userId');

    $function = (true === $args['dismissed']) ? "in" : "notIn";
    $expr = $qb->expr()->$function($this->classAlias.'.id', $dismissedQB->getDQL());

    /** @var $qb QueryBuilder */
    $qb->andWhere($expr)
       ->setParameter("entityDiscriminator", HelpDocument::getDiscriminator())
       ->setParameter("event", HelpDocumentEvents::HELPDOCUMENT_DISMISS)
       ->setParameter("userId", $args["user"]);

//  exit($result = $qb->getQuery()->getSQL());

    return $qb;
}

此 DQL 查询产生以下 SQL:

SELECT h0_.id AS id0
FROM HelpDocument h0_ 
WHERE (
    h0_.id NOT IN (
        SELECT l1_.entity_id 
        FROM LogEntry l1_ 
        WHERE l1_.entityDiscriminator = 'helpDocument' 
        AND l1_.event = 'helpDocument.dismiss' 
        AND l1_.user_id = 1
    )
)

耶!

最佳答案

我看到了你的解决方案,我做了一个小改动,这将是一个巨大的性能改进。特别是如果您有几千行以上。

public function filterQueryByUserDismissed(QueryBuilder $qb, $args)
{
  $args = array_merge(array(
    "user" => null,
    "dismissed" => false
  ), $args);

  /** @var $dismissedQB QueryBuilder */
  $dismissedQB = $this->_em->createQueryBuilder();

  /*
  This line is important. We select an alternative attribute rather than
  letting Doctrine select le.id
  */
  $dismissedQB->select('le.entityId')
            ->from('\Mlf\AppBundle\Entity\UserEntityEventLog', 'le')
            ->where('le.entityDiscriminator = :entityDiscriminator')
            ->andWhere('le.event = :event')
            ->andWhere('le.user = :userId');

  // ---- My changes below
  // Get an array with the ids
  $dismissedIdsMap = $dismissedQB->getQuery()->getResults();
  $dismissedIds = array_map(
        function($a){
            return $a['entityId'];
        },
        $dismissedIdsMap);

  $function = (true === $args['dismissed']) ? "in" : "notIn";
  $expr = $qb->expr()->$function($this->classAlias.'.id', $dismissedIds);
  // ---- My changes above

  /** @var $qb QueryBuilder */
  $qb->andWhere($expr)
   ->setParameter("entityDiscriminator", HelpDocument::getDiscriminator())
   ->setParameter("event", HelpDocumentEvents::HELPDOCUMENT_DISMISS)
   ->setParameter("userId", $args["user"]);

  //  exit($result = $qb->getQuery()->getSQL());

  return $qb;
}

上面的代码使用了两个查询。如果您使用一个查询,MySQL 将从您的子查询创建一个临时 View ,然后使用主查询查询该 View 。创建此 View 的开销很大。通过两个查询,您将在 PHP 内存 中保留“ View ”,这将显着减少开销。

关于symfony - Doctrine2 - 没有关系的子查询连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14349366/

相关文章:

doctrine-orm - 如何使用 doctrine2 zf2 在 View 助手中获取实体管理器

mysql - Symfony 2 DQL 查询查找未翻译的记录

mysql - 是否可以使用 Doctrine 导出 CSV 文件?

java - DQL 在 DFC 中删除 group_name

php - 如何根据 session 中的值使用 Assetic 嵌入样式表

php - Symfony2 和 MongoDB : FormType of a document with references

SQLSTATE[08006] [7] 无法将主机名 "dbname="转换为地址

symfony - 如果没有默认 Controller /操作,登录 check_path 路由如何工作?

php - Symfony2 的 Doctrine 不会为我创建一对多结构

php - 没有创建数据库的 Symfony 2.7 应用程序