我有两个与OneToMany关系相关的实体:
<?php
namespace CRMBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* User
*
* @ORM\Table()
* @ORM\Entity(repositoryClass="CRMBundle\Entity\ContactRepository")
*/
class User
{
/*...*/
/**
* @ORM\OneToMany(targetEntity="CRMBundle\Entity\Message", mappedBy="user", cascade={"persist"})
* @ORM\OrderBy({"datetime" = "DESC"})
*/
protected $messages;
/*...*/
}
和
<?php
namespace CRMBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Message
*
* @ORM\Table()
* @ORM\Entity
*/
class Message
{
/*...*/
/**
* @ORM\ManyToOne(targetEntity="CRMBundle\Entity\User", inversedBy="messages")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="SET NULL")
*/
private $user;
/**
* @var \DateTime
*
* @ORM\Column(name="Datetime", type="datetime", nullable=true)
*/
private $datetime;
/*...*/
}
我的问题是如何在UserController中创建一个查询,以便为每个用户提供每个用户的最后一条消息(即根据datetime属性的最新消息)?
答案 0 :(得分:4)
我认为您要找的是one of my previous answers到one of my own questions ^^
您必须使用子查询动态选择一个用户的消息的最新日期时间值,并加入具有此值的消息。
为此,您必须定义(子)查询,选择message.datetime的MAX值:
$qb2= $this->createQueryBuilder('ms')
->select('MAX(ms.datetime) maxDate')
->where('ms.user = u')
;
然后在你的join子句中使用它,整个函数在你的UserRepository中:
$qb = $this->createQueryBuilder('u');
$qb ->leftJoin('u.messages', 'm', 'WITH', $qb->expr()->eq( 'm.datetime', '('.$qb2->getDQL().')' ))
->addSelect('m');
您的用户(他们每个人)将有一个消息Collection,其中包含一个消息(如果没有来自用户的消息,则为null)消息,您将通过这种方式获得:
$user->getMessages()->first();
但是如果你使用Symfony的延迟加载函数,因为你已经在user.messages属性上定义了一个orderby注释,调用
$user->getMessages()->first()
应该向您返回最新消息(但也会以静默方式加载所有其他消息)。 要避免此静默的第二个数据库查询,您可以将其直接加入请求您的用户的查询中:
$qb = $this->createQueryBuilder('u');
$qb ->leftJoin('u.messages', 'm')
->addSelect('m');