我正在学习有关Symfony和Doctrine的知识,并创建了一个简单的网站,但在这一步中我陷入了困境。
我有两个表:users
和languages
用户包含:ID,用户名...
语言,包含:user_id,语言...
现在,我正在尝试按语言获取信息,例如:获取同时说english
和 french
的用户,结果将返回用户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();
}
我在控制器中调用此方法,并且查询非常基本,因为找不到根据我的示例进行连接的文档
答案 0 :(得分:6)
在您的用户模型中添加下一个代码:
$post = Post::find(1); dd($post->images)
在您的语言模型中添加下一个代码:
/**
* @ORM\OneToMany(targetEntity="Language", mappedBy="user", fetch="EXTRA_LAZY")
*/
public $languages;
通过这种方式,您可以在用户和语言之间定义简单的一对多关系,但这不足以让您的用户支持两种语言。您需要将用户表和语言表进行2次连接。 就是这样(如果使用控制器):
/**
* @ORM\ManyToOne(targetEntity="User", inversedBy="languages")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
* })
*/
public $user;
或者,如果您使用UserRepository类(最好):
$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();
因此,主要技巧是加入具有英语条件的语言表以过滤支持英语的用户 AND 再次加入语言表,但在“ ON”部分中添加法语以过滤支持法语的用户<也是。
答案 1 :(得分:2)
通过分析数据库表,我假设您的实体是这样的
// User.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;
}
// Language.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();
}
这将返回结果数组。
答案 2 :(得分:0)
也许我对问题的理解不正确,如果我错了,请纠正我,但是如果您需要使用两种语言的用户,则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解释。
答案 3 :(得分:0)
您可以:
代码:
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 having“检查”每个用户是否有2行来实现的。
如果您还希望将Languages实体添加到结果中,则不能将其添加到querybuilder结果中,因为按以下条件进行了分组
-> addSelect('a')
您将不得不再次进行查询。