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) 并加入两次以从语言中获取位置。
我正在使用以下查询:
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) 并加入两次以从语言中获取位置。