Yii2多对多关系:在联结表

时间:2016-08-17 17:53:29

标签: php sql activerecord yii2

只是为了先发制人,认为这是thisthisthis等问题的重复:这些情况有所不同,因为他们谈论的是全部B项目,按联结表字段定义的顺序,用于特定A项。我正在谈论查询许多A项目,并且对于每个A项目,急切地按照联结表格中的字段定义的顺序加载其B项目。

假设您有paperauthor个表,这些表是多对多的,通过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');
                }
            )
    }

    // ...
}
?>

但是,这不起作用,因为正在修改的$querypaper_author上的SELECT,其目的是获取author_id列表。之后,另一个SELECT查询在带有author的{​​{1}}表上运行,但该查询的结果不符合赋予IN()函数的ID的顺序 - 这不是如何IN()有效。

即使您可以使该查询的结果 尊重该订单,您也会遇到此问题:查询会返回一个作者列表,其中每个作者只出现一次。这使它变得高效。但是,给定的作者可能会附加到您正在显示的论文列表中的多篇论文中。作者顺序(WHERE id IN (...author_ids...))不是作者的属性;它是作者论文 relation 的一个属性。

这是Yii2能够解决的问题,我不知道吗?或者是否需要一些自定义结果处理?

1 个答案:

答案 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