如何使用doctor/symfony4从数据库中获取(连接)两条记录

9rnv2umw  于 2021-06-20  发布在  Mysql
关注(0)|答案(4)|浏览(354)

我正在学习symfony和学说,并创建了一个简单的网站,但我在这一步卡住了。
我有两张table: users 以及 languages 用户包含:id、用户名。。。
语言包含:用户id、语言。。。
这是两人的照片


现在我正在尝试通过语言获取,比如:获取同时使用这两种语言的用户 englishfrench 结果将返回用户id 2
在普通php中,我可以使用pdo进行内部连接,但是我试图遵循原则语法,这不会返回正确的结果

  1. public function getMatchingLanguages ($a, $b) {
  2. return $this->createQueryBuilder('u')
  3. ->andWhere('u.language = :val1 AND u.language = :val2')
  4. ->setParameter('val1', $a)
  5. ->setParameter('val2', $b)
  6. ->getQuery()
  7. ->execute();
  8. }

我在我的控制器中调用这个方法,查询是非常基本的,因为我找不到如何按照我的示例进行连接的文档

6psbrbz9

6psbrbz91#

在用户模型中添加下一个代码:

  1. /**
  2. * @ORM\OneToMany(targetEntity="Language", mappedBy="user", fetch="EXTRA_LAZY")
  3. */
  4. public $languages;

在语言模型中添加下一个代码:

  1. /**
  2. * @ORM\ManyToOne(targetEntity="User", inversedBy="languages")
  3. * @ORM\JoinColumns({
  4. * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
  5. * })
  6. */
  7. public $user;

通过这种方式,您可以在用户和语言之间定义简单的一对多关系,但这还不足以让您的用户同时支持这两种语言。你需要做两个用户表和语言表的连接。这就是它的样子(如果您使用控制器):

  1. $user = $this->get('doctrine')
  2. ->getEntityManager()
  3. ->createQueryBuilder()
  4. ->select('u')
  5. ->from(User::class, 'u')
  6. ->join('u.languages', 'l_eng', 'WITH', 'l_eng.language = :engCode')
  7. ->join('u.languages', 'l_fr', 'WITH', 'l_fr.language = :frCode')
  8. ->setParameters([
  9. 'engCode' => 'english',
  10. 'frCode' => 'french'
  11. ])
  12. ->getQuery()->execute();

或者,如果您使用userrepository类(最好是):

  1. public function findAllByLangs()
  2. {
  3. return $this->createQueryBuilder('u')
  4. ->join('u.languages', 'l_eng', 'WITH', 'l_eng.lang = :engCode')
  5. ->join('u.languages', 'l_fr', 'WITH', 'l_fr.lang = :frCode')
  6. ->setParameters([
  7. 'engCode' => 'english',
  8. 'frCode' => 'french'
  9. ])
  10. ->getQuery()->execute();
  11. }

所以主要的技巧是用英语条件连接语言表来过滤用户,即支持英语的用户再连接语言表,但在“on”部分用法语来过滤支持法语的用户。

展开查看全部
cx6n0qe3

cx6n0qe32#

也许我没有正确理解这个问题,请纠正我,如果我错了,但如果你需要用户(s)说两种语言,你有一个错误的sql逻辑,而不是在条令。你应该这样做:

  1. SELECT * FROM user u JOIN language l ON u.id = l.user_id AND l.language = 'english' JOIN language l2 ON u.id = l2.user_id AND l2.language = 'french' GROUP BY u.id;

如果您的查询正确,我可以为它编写dql解释。

rn0zuynd

rn0zuynd3#

你可以:
与你想要的语言内在连接
使用聚合函数计算联接结果(联接语言)
按用户实体分组
过滤count(lang)=2的结果
代码:

  1. use Doctrine\ORM\Query\Expr\Join;
  2. public function getMatchingLanguages ($a, $b) {
  3. return $this->createQueryBuilder('u')
  4. ->addSelect('COUNT(a) as HIDDEN total')
  5. ->innerJoin('u.languages', 'a', Join::WITH, 'a.language = :val1 OR a.language = :val2')
  6. ->groupBy('u');
  7. ->having('total = :total') //or ->having('COUNT(a) = :total')
  8. ->setParameter('total', 2)
  9. ->setParameter('val1', $a)
  10. ->setParameter('val2', $b)
  11. ->getQuery()
  12. ->execute();
  13. }
  14. $this->getMatchingLanguages('english', 'french');

它的工作原理是只在用户内部连接英语或法语的行,然后使用mysql检查每个用户是否有2行。
如果还希望将语言实体添加到结果中,则不能将其添加到querybuilder结果中,因为分组依据:
->addselect('a')
你必须再做一次查询。

展开查看全部
tag5nh1u

tag5nh1u4#

通过分析db表,我假设您的实体是这样的
//用户.php

  1. class User implements UserInterface
  2. {
  3. /**
  4. * @ORM\Column(type="guid")
  5. * @ORM\Id
  6. * @ORM\GeneratedValue(strategy="UUID")
  7. */
  8. private $id;
  9. /**
  10. * @ORM\Column(type="string", length=100)
  11. */
  12. private $username;
  13. }

//语言.php

  1. class Language
  2. {
  3. /**
  4. * @ORM\Column(type="guid")
  5. */
  6. private $userId;
  7. /**
  8. * @ORM\Column(type="string", length=30)
  9. */
  10. private $language;
  11. }

如果您有相同的设置(与上面的实体相同),那么您可以在userrepository.php中这样编写查询

  1. public function getUsersForMatchingLanguages ($langOne, $langTwo) {
  2. return $this->createQueryBuilder('user')
  3. ->select('user.id, user.username, language.language')
  4. ->innerJoin(Language::class, 'language', 'WITH', 'language.user_id = user.id')
  5. ->where('language.language = :langOne AND language.language = :langTwo')
  6. ->setParameter('langOne ', $langOne )
  7. ->setParameter('langTwo', $langTwo)
  8. ->getQuery()
  9. ->getResult();
  10. }

这将返回一组结果。

展开查看全部

相关问题