Doctrine left join with priority on language field with querybuilder

Doctrine left join with priority on language field with querybuilder

我正在使用以下查询:

use Doctrine\ORM\Query\Expr\Join;

$query = $this->createQueryBuilder('ad')
    ->select('ad.id, ad.title, ad.year, ad.hours, ad.status')
    ->addSelect('rem.remark')
    ->leftJoin('ad.remark', 'rem', Join::WITH, "rem.language = 'NL'")
    ->getQuery()
    ->getResult();

此查询运行良好,returns 荷兰语广告的评论。广告与其备注是一对多关系。

只有我也有广告,例如有英文备注而不是荷兰文。我想得到那个的英语评论,而列表中的其他人仍然是荷兰语评论。总结一下,为返回的语言列出优先级列表?

解决这个问题的一种方法是使用 额外的 :

$query = $this->createQueryBuilder('ad')
    ->select('ad.id, ad.title, ad.year, ad.hours, ad.status')
    ->addSelect('rem.remark')
    ->leftJoin('ad.remark', 'rem', Join::WITH, "rem.language = 'NL' OR rem.language = 'EN'")
    ->leftJoin(Remark::class, 'customRem', Join::WITH, 
    "rem.id <> customRem.id 
    AND rem.ad = customRem.ad 
    AND customRem.language = 'NL'")
    ->where('customRem.id IS NULL')
    ->getQuery()
    ->getResult();

想法是

  • 如果广告存在 NL 语言备注,则将此备注添加到该广告预期的每个结果行本身(将为空)
  • 如果NL语言备注不存在,而EN存在,则合并行为空

最后,条件 customRem.id IS NULL 使这项工作成功。

多语言解决方案

在支持 3 种语言的情况下,因为 DE > EN > NL,你可以这样做:

->leftJoin(Remark::class, 'customRem', Join::WITH,        
     "rem.id <> customRem.id AND rem.ad = 
      customRem.ad AND rem.language < customRem.language")

对于多种语言,假设具有“自定义”的能力来对语言进行排序,您可以使用:

"rem.id <> customRem.id 
AND rem.ad = customRem.ad AND 
(case when rem.language = 'NL' THEN 3 " .
"when rem.language = 'EN' THEN 2 " .
"when rem.language = 'DE' THEN 1 ELSE 0 END) < (case when customRem.language = 'NL' THEN 3 " .
"when customRem.language = 'EN' THEN 2 " .
"when customRem.language = 'DE' THEN 1 ELSE 0 END)"

或者,您可以创建 "lang_position" table(id, language, position) 并加入两次以从语言中获取位置。