只是为了先发制人,认为这是this,this或this等问题的重复:这些情况有所不同,因为他们谈论的是全部B项目,按联结表字段定义的顺序,用于特定A项。我正在谈论查询许多A项目,并且对于每个A项目,急切地按照联结表格中的字段定义的顺序加载其B项目。
假设您有paper
和author
个表,这些表是多对多的,通过paper_author
表关联。但对于学术论文,作者的顺序很重要,因此paper_author
表格有一个数字rank
字段。
现在您要显示所有论文标题的列表,并且要在每篇论文的标题旁边列出作者,以正确的顺序。如果论文列表长达100篇,您还需要热心地加载作者以防止必须运行100个作者查询。
您已经设置了标准的Yii2 ActiveRecord关系。所以你做了类似的事情,
<?php
$papers = Paper::find()->with('authors')->all();
foreach ($papers as $paper) {
echo "Title: " . $paper->title . "\n"
. "Authors: ";
foreach ($paper->authors as $author) {
echo $author->name . " ";
}
echo "\n";
}
?>
然而,每篇论文的作者都以不确定的顺序出现。好的,所以你对Paper
类中作者关系的声明进行了特殊的更改:
<?php
class Paper extends ActiveRecord {
// ...
public function getAuthors() {
return $this
->hasMany(Author::className(), ['id' => 'author_id'])
->viaTable('paper_author', ['paper_id' => 'id'],
// SPECIAL CHANGE: 3rd param to viaTable()
function ($query) {
$query->orderBy('rank');
}
)
}
// ...
}
?>
但是,这不起作用,因为正在修改的$query
是paper_author
上的SELECT,其目的是获取author_id列表。之后,另一个SELECT查询在带有author
的{{1}}表上运行,但该查询的结果不符合赋予IN()函数的ID的顺序 - 这不是如何IN()有效。
即使您可以使该查询的结果 尊重该订单,您也会遇到此问题:查询会返回一个作者列表,其中每个作者只出现一次。这使它变得高效。但是,给定的作者可能会附加到您正在显示的论文列表中的多篇论文中。作者顺序(WHERE id IN (...author_ids...)
)不是作者的属性;它是作者论文 relation 的一个属性。
这是Yii2能够解决的问题,我不知道吗?或者是否需要一些自定义结果处理?
答案 0 :(得分:0)
我认为对于这种情况,正确的方法是为联结表定义额外的AR类,因为它不仅是多对多链接,而且还有自己的含义 - 订单位置作者名单中的作者。
所以,当你有像PaperAuthorship
之类的课程时( Paper , PaperAuthorship 和作者之间有适当的关系) )你将能够以这种方式执行你的查询:
$papers = Paper::find()
->with('paperAuthorships', 'paperAuthorships.author')
->all();
foreach ($papers as $paper) {
echo "Title: " . $paper->title . "\n"
. "Authors: ";
foreach ($paper->paperAuthorships as $paperAuthorship) {
echo $paperAuthorship->author->name . " ";
}
echo "\n";
}
实现正确的排序顺序非常容易(例如关系Paper.paperAuthorships
)