Symfony 多对多-获取用户的线程
我正在编写一个私有消息系统,我遇到了一个问题,无法正确获取用户的线程列表 我有3个实体: 使用者 线 邮递 线程实体具有多对多关系: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-&
/**
* @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日重复行相同。这里没有重复任何内容,我使用您的实体代码。你能说得更具体些吗?