简体   繁体   English

在1个Dctrine DQL中合并2个查询

[英]Merge 2 queries in 1 Doctrine DQL

I'm using Doctrine 2.4 with Symfony 2.8 and I'm trying to build a friendship system. 我正在使用带有Symfony 2.8的Doctrine 2.4,并且正在尝试建立一个友谊系统。

I have my MateRelationship entity : 我有MateRelationship实体:

class MateRelationship
{
    /**
     * @var integer
     *
     * @ORM\Column(type="integer", name="id")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User")
     * @ORM\JoinColumn(name="sender", referencedColumnName="id", nullable=false)
     *
     */
    private $sender;

    /**
     * @ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User")
     * @ORM\JoinColumn(name="receiver", referencedColumnName="id", nullable=false)
     *
     */
    private $receiver;

    /**
     * @var \DateTime
     *
     * @ORM\Column(type="datetime", nullable=false)
     */
    private $date;

    /**
     * @var boolean
     *
     * @ORM\Column(type="boolean", nullable=false)
     */
    private $invitationAccepted;

My goal is to make a DQL query to get all accepted friends relationship for a given user (no matter if the user is sender or receiver) . 我的目标是进行DQL查询,以获取给定用户的所有接受的朋友关系(无论用户是发送者还是接收者)。

I managed to do it with 2 queries and by merging results, but it's not optimized and it's harder to implement $limit this way. 我设法通过2个查询并合并结果来完成此操作,但是它没有经过优化,因此很难以这种方式实现$limit

public function getMates($user, $limit = 0){

    $query1 = $this->_em->createQuery('SELECT m, u.nickname, u.username FROM AcmeUserBundle:MateRelationship m JOIN m.receiver u WHERE m.invitationAccepted = 1 AND m.sender = :user')
            ->setParameter('user', $user);

    try{
        $result1 = $query1->getResult();
    }
    catch(\Doctrine\ORM\NoResultException $e){
        $result1 = [];
    }

    $query2 = $this->_em->createQuery('SELECT m, u.nickname, u.username FROM AcmeUserBundle:MateRelationship m JOIN m.sender u WHERE m.invitationAccepted = 1 AND m.receiver = :user')
            ->setParameter('user', $user);

    try{
        $result2 = $query2->getResult();
    }
    catch(\Doctrine\ORM\NoResultException $e){
        $result2 = [];
    }

    return array_merge($result1, $result2);
}

I'd like to have a single query so I could use ->setMaxResults($limit) but I have no idea how to merge these 2 queries in 1. Thanks for your help :) 我想要一个查询,所以可以使用->setMaxResults($limit)但我不知道如何在1中合并这两个查询。感谢您的帮助:)

You can do this using LEFT JOIN and CASE to obtain the valid user information: 您可以使用LEFT JOINCASE来获得有效的用户信息:

    public function getMates($user, $limit = 0)
    {
        $dql = <<<DQL
            SELECT 
               m, 
               CASE usen.nickname IS NULL WHEN TRUE THEN urec.nickname ELSE usen.nickname END AS nickname, 
               CASE usen.username IS NULL WHEN TRUE THEN urec.username ELSE usen.username END AS username, 
               CASE usen.nickname IS NULL WHEN TRUE THEN 'sender' ELSE 'receiver' END AS relationship
            FROM AcmeUserBundle:MateRelationship m 
            LEFT JOIN m.sender usen 
            LEFT JOIN m.receiver urec 
            WHERE m.invitationAccepted = 1 AND (m.receiver = :user OR m.sender= :user)
DQL;

        return $this->_em->createQuery($dql)
            ->setParameter('user', $user)
            ->setMaxResults($limit)
            ->getResult();
    }

If the $result is empty it's already an empty array [] . 如果$result为空,则它已经是一个空数组[]

Note: The NoResultException exception only is thrown for getOneOrNullResult , getSingleResult or getSingleScalarResult methods they are invoked. 注意:仅针对调用它们的getOneOrNullResultgetSingleResultgetSingleScalarResult方法引发NoResultException异常。

Here's a proposal using the doctrine query builder 这是使用原则查询构建器的建议

public function getMates($user, $limit = 0)
{
    // Create query builder
    $queryBuilder = $this->_em->getRepository("AcmeUserBundle:MateRelationship")->createQueryBuilder('m');

    // Create 'or' expression
    $or = $queryBuilder->expr()->orX();
    $or
        ->add('m.sender = :user')
        ->add('m.receiver = :user');

    // Create the query
    $queryBuilder
        ->andWhere('m.invitationAccepted = 1')
        ->andWhere($or)
        ->setMaxResults($limit)
        ->setParameter('user', $user);

    // Return the result
    return $queryBuilder->getQuery()->getResult();
}

You can simply do it by putting OR when you match :user . 您可以简单地通过在匹配:user时输入OR来实现。 That can be either receiver OR sender . 那可以是receiver也可以是sender

SELECT m, usen.nickname, usen.username, urec.nickname, urec.username
FROM AcmeUserBundle:MateRelationship m 
JOIN m.sender usen 
JOIN m.receiver urec 
WHERE m.invitationAccepted = 1 AND 
(m.receiver = :user OR m.sender= :user)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM