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

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

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


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

public function getMatchingLanguages ($a, $b) {
  return $this->createQueryBuilder('u')
    ->andWhere('u.language = :val1 AND u.language = :val2')
    ->setParameter('val1', $a)
    ->setParameter('val2', $b)
    ->getQuery()
    ->execute();
}

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

6psbrbz9

6psbrbz91#

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

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

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

/**
 * @ORM\ManyToOne(targetEntity="User", inversedBy="languages")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="user_id", referencedColumnName="id")
 * })
 */
public $user;

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

$user = $this->get('doctrine')
        ->getEntityManager()
        ->createQueryBuilder()
        ->select('u')
        ->from(User::class, 'u')
        ->join('u.languages', 'l_eng', 'WITH', 'l_eng.language = :engCode')
        ->join('u.languages', 'l_fr', 'WITH', 'l_fr.language = :frCode')
        ->setParameters([
            'engCode' => 'english',
            'frCode' => 'french'
        ])
        ->getQuery()->execute();

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

public function findAllByLangs()
{
    return $this->createQueryBuilder('u')
        ->join('u.languages', 'l_eng', 'WITH', 'l_eng.lang = :engCode')
        ->join('u.languages', 'l_fr', 'WITH', 'l_fr.lang = :frCode')
        ->setParameters([
            'engCode' => 'english',
            'frCode' => 'french'
        ])
        ->getQuery()->execute();
}

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

cx6n0qe3

cx6n0qe32#

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

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的结果
代码:

use Doctrine\ORM\Query\Expr\Join;

public function getMatchingLanguages ($a, $b) {
    return $this->createQueryBuilder('u')
                ->addSelect('COUNT(a) as HIDDEN total')
                ->innerJoin('u.languages', 'a', Join::WITH, 'a.language = :val1 OR a.language = :val2')
        ->groupBy('u');
                 ->having('total = :total') //or ->having('COUNT(a) = :total')
        ->setParameter('total', 2)
        ->setParameter('val1', $a)
        ->setParameter('val2', $b)
        ->getQuery()
        ->execute();
}

$this->getMatchingLanguages('english', 'french');

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

tag5nh1u

tag5nh1u4#

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

class User implements UserInterface
{
    /**
     * @ORM\Column(type="guid")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="UUID")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=100)
     */
    private $username;
}

//语言.php

class Language
{

    /**
     * @ORM\Column(type="guid")
     */
    private $userId;

    /**
     * @ORM\Column(type="string", length=30)
     */
    private $language;
}

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

public function getUsersForMatchingLanguages ($langOne, $langTwo) {
    return $this->createQueryBuilder('user')
        ->select('user.id, user.username, language.language')
        ->innerJoin(Language::class, 'language', 'WITH', 'language.user_id = user.id')
        ->where('language.language = :langOne AND language.language = :langTwo')
        ->setParameter('langOne ', $langOne )
        ->setParameter('langTwo', $langTwo)
        ->getQuery()
        ->getResult();
}

这将返回一组结果。

相关问题