Symfony 多对多-获取用户的线程

Symfony 多对多-获取用户的线程,symfony,doctrine-orm,Symfony,Doctrine Orm,我正在编写一个私有消息系统,我遇到了一个问题,无法正确获取用户的线程列表 我有3个实体: 使用者 线 邮递 线程实体具有多对多关系: /** * @ORM\ManyToMany(targetEntity="Acme\UserBundle\Entity\User", cascade={"persist"}) */ private $users; 我有一个查询正在工作,以实现接近我想要的目标: public function getThreads($user) { $q = $this-&

我正在编写一个私有消息系统,我遇到了一个问题,无法正确获取用户的线程列表

我有3个实体:

使用者 线 邮递 线程实体具有多对多关系:

/**
* @ORM\ManyToMany(targetEntity="Acme\UserBundle\Entity\User", cascade={"persist"})
*/
private $users;
我有一个查询正在工作,以实现接近我想要的目标:

public function getThreads($user) {
    $q = $this->createQueryBuilder('t')
                ->leftJoin('t.users', 'u')
                    ->addSelect('u')
                ->where('u.id = :user')
                ->setParameter('user', $user)
                ->orderBy('t.date', 'DESC')
                ->setMaxResults(20);

    return $q->getQuery()->getResult();
}
public function getThreads($user) {
   $q = $this->createQueryBuilder('t');
                $q->leftJoin('t.users', 'u', \Doctrine\ORM\Query\Expr\Join::WITH, $q->expr()->eq('u.id', ':user'))
                ->leftJoin('t.users', 'u2', \Doctrine\ORM\Query\Expr\Join::WITH, $q->expr()->neq('u2.id', ':user'))
                    ->addSelect('partial u2.{xxx, xxx, ...}')
                ->where('u.id = :user')
                ->setParameter('user', $user)
                ->orderBy('t.date', 'DESC')
                ->setMaxResults(20);

    return $q->getQuery()->getResult();
}
但我的名字出现在线程列表中:

 From     | Text           | date   
----------|----------------|--------
 Hotgeart | Hello :)       | 31 jan 
 Hotgeart | Wanna go out?  | 20 jan 
 Hotgeart | I love book    | 10 jan 
显然,我想得到的是踏板的另一个用户的名字,而不是我的:

 From     | Text           | date   
----------|----------------|--------
 Homer    | Hello :)       | 31 jan 
 Bart     | Wanna go out?  | 20 jan 
 Lisa     | I love book    | 10 jan 
要获得上述正确结果,我需要在查询中更改哪些内容

附言:它可以是一个DQL查询

编辑完整实体:

我快到了 2月3日编辑:

我有一些接近我想要的东西:

public function getThreads($user) {
    $q = $this->createQueryBuilder('t')
                ->leftJoin('t.users', 'u')
                    ->addSelect('u')
                ->where('u.id = :user')
                ->setParameter('user', $user)
                ->orderBy('t.date', 'DESC')
                ->setMaxResults(20);

    return $q->getQuery()->getResult();
}
public function getThreads($user) {
   $q = $this->createQueryBuilder('t');
                $q->leftJoin('t.users', 'u', \Doctrine\ORM\Query\Expr\Join::WITH, $q->expr()->eq('u.id', ':user'))
                ->leftJoin('t.users', 'u2', \Doctrine\ORM\Query\Expr\Join::WITH, $q->expr()->neq('u2.id', ':user'))
                    ->addSelect('partial u2.{xxx, xxx, ...}')
                ->where('u.id = :user')
                ->setParameter('user', $user)
                ->orderBy('t.date', 'DESC')
                ->setMaxResults(20);

    return $q->getQuery()->getResult();
}
是的,给我这张桌子:

 From     | Text           | date   
----------|----------------|--------
 NULL     | Hello :)       | 31 jan 
 Homer    | Hello :)       | 31 jan 
 NULL     | Wanna go out?  | 20 jan 
 Bart     | Wanna go out?  | 20 jan 
 NULL     | I love book    | 10 jan 
 Lisa     | I love book    | 10 jan 
如果我有一个->addSelect'partial u2.{xxx,xxx,…}到第一个连接,我有相同的表,但是空值被hotgeart me替换

public function getThreads($user) {
    $q = $this->createQueryBuilder('t')
            ->leftJoin('t.users', 'u')
                ->addSelect('u')
            ->where('u.id = :user')
            ->setParameter('user', $user)//limits result to user $user
            ->orderBy('t.date', 'DESC')
            ->setMaxResults(20);

    return $q->getQuery()->getResult();
}
您必须将其替换为in/EXISTS。

您应该将您的Post映射更正为一个多用户:

/**
 * @ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User", cascade={"persist"})
 */
 private $user;
您的查询将如下所示:

public function getThreads($user) {
    $q = $this->createQueryBuilder('t')
                ->leftJoin('t.posts', 'p')
                ->leftJoin('p.user', 'u')
                ->addSelect('t')
                ->where('u.id = :user')
                ->setParameter('user', $user)
                ->orderBy('t.date', 'DESC')
                ->setMaxResults(20);

    return $q->getQuery()->getResult();
}

这样,您就只有线程实体了。顺便说一句,您不会直接从线程实体获取用户,因为您不会事先知道该线程中的哪些帖子是由他编写的

您可以通过下一种方式获得线程:

public function getThreads($user) {
    $em     = $this->getEntityManager();

    $query  = $em->createQuery(
        'SELECT     t
         FROM       AcmeMessageBundle:Thread t
         WHERE      :user MEMBER OF t.users
         ORDER BY   t.date DESC'
    )
    ->setParameter('user', $user)
    ->setMaxResults( 20 );

    $threads  = $query->getResult();

    return $threads;
}
您将收到一个Doctrine ArrayCollection,其中包含删除AcmeMessageBundle并输入正确的捆绑名称所需的线程

编辑: 再次阅读您的问题,并查看您的示例,我认为您想要的不是线程,而是与用户相关的线程的帖子。您可以在帖子和线程实体之间添加双向关系,如下所示:

在线程实体中,添加以下内容:

/**
 * @ORM\OneToMany(targetEntity="\Acme\MessageBundle\Entity\Post", mappedBy="thread")
 */
private $posts;
在构造函数中:

$this->posts = new \Doctrine\Common\Collections\ArrayCollection();
在Post实体中,按如下方式修改行:

/**
* @ORM\ManyToOne(targetEntity="Acme\MessageBundle\Entity\Thread", inversedby="posts")
* @ORM\JoinColumn(nullable=false)
*/
private $thread;

并为线程实体中的帖子生成getter和setter,这样,在获得如上所述的线程后就可以获得帖子。

我认为您在这里遇到了一些设计问题

根据我的理解,线程是由用户发起的讨论。帖子是线程中的单个消息

如果你能解释你是如何计划工作的,那么说你的实体应该如何关联就容易多了。据我所知你的问题

如果消息仅发生在两个人之间,则不需要多对多关系。在线程实体中,您只需要具有与用户的多通关联的发送方和接收方属性。你的帖子看起来不错。然后回到你的人那里

由用户获取线程列表:

 $q = $this->createQueryBuilder('t')
            ->select('s.username', 't.message', 't.date') // assuming the fields
            ->join('t.sender', 's')
            ->join('t.receiver', 'u')
            ->where('u.id = :user')
            ->setParameter('user', $user)
            ->orderBy('t.date', 'DESC')
            ->setMaxResults(20);

return $q->getQuery()->getResult();

为了让人们参与到一个线程中,你必须对你的查询进行一些改进。目前,您正在按用户id进行筛选,以获取用户所在的线程。但是,这并不能让您了解处于该线程中的其他用户的预期行为,因此出现了问题

你要做的是:

首先,找出用户所在的线程。 第二,检索包含所有用户的线程。 这可以在单个查询中混合使用:

$em = $this
        ->getDoctrine()
        ->getManager();// Entity manager, I'm using SF and querying in a controller for a simplicity. You can adapt it to a Repository if you like.

$dql = $em
        ->getRepository("AcmeDemoBundle:Thread")// Change this to suit you
        ->createQueryBuilder('t2')
        ->select('t2.id')
        ->leftJoin('t2.users', 'u2')
        ->where('u2.id = :user')
        ->getDQL();// Subquery that will retrieve those threads in which user with id = $user is involved.

$qb = $em
        ->getRepository("AcmeDemoBundle:Thread")// Change this to suit you
        ->createQueryBuilder('t');// Querybuilder object: useful for the 'in' part of the query.

$q2 = $qb
        ->addSelect('u')
        ->leftJoin('t.users', 'u')
        ->andWhere($qb->expr()->in('t.id', $dql))
        ->setParameter('user', 1)// I force 1 for simplicity, you can use a variable.
        ->orderBy('t.date', 'DESC')
        ->setMaxResults(20)
        ->getQuery()
        ->getResult();// Retrieve threads in which user is in. Each thread will have in users those users involved in the thread.
结果,此查询将有一个线程数组,用户在其中。每个线程的users变量中都包含参与线程的用户列表。用户将位于这些用户变量中。如果您喜欢添加->例如,where'u.id:user',您可以在查询中过滤它


希望有帮助。

嘿,Hotgeart,我想看看您所有的实体类定义,这样我可以更好地理解这个问题。你能把定义放在一个粘贴中吗?我编辑过,在我的user.php中没有提到thread或post。哪个用户应该出现在“From”列中?启动线程的人,最后一个如何向线程发送帖子或线程的所有参与者?一次对话中总是有两个用户。当一个用户想要获取他的对话列表时,它应该显示另一个用户的名字。同样的结果,但是在symfony后面为每个线程创建一个“获取用户我而不是另一个”的查询。您可以在此处看到查询:。没有办法保留我的查询并对sql说要加入其他用户?还是我的私人信息系统逻辑不好?这是一个很好的方法,不是吗?不是,post对于获取线程信息是无用的,所有信息都在thread和thread_user表中。我在实体线程中有一个文本缓存和日期缓存,用户在用户创建的线程中。所以我已经得到了帖子的信息。根据你的查询,我只有50%的帖子。当我是接受者的时候,我只能得到线程。如果我是发信人呢?我需要一个手术室。或者吃太多的蔬菜。我已经有了一个MP系统,就是这样。这就是我重新编码的原因。我的设计是代码,只是需要好的查询。我的结果与我的编辑2月3日重复行相同。这里没有重复任何内容,我使用您的实体代码。你能说得更具体些吗?