【问题标题】:Yii2: What is the correct way to define relationships among multiple tables?Yii2:定义多个表之间关系的正确方法是什么?
【发布时间】:2015-10-28 09:20:33
【问题描述】:

在控制器中我有以下代码:

public function actionView($id)
{
    $query = new Query;
    $query->select('*')
        ->from('table_1 t1')
        ->innerJoin('table_2 t2', 't2.t1_id = t1.id')
        ->innerJoin('table_3 t3', 't2.t3_id = t3.id')
        ->innerJoin('table_4 t4', 't3.t4_id = t4.id')
        ->andWhere('t1.id = ' . $id);
    $rows = $query->all();
    return $this->render('view', [
        'model' => $this->findModel($id),
        'rows' => $rows,
        ]);
}

查看数据库架构:https://github.com/AntoninSlejska/yii-test/blob/master/example/sql/example-schema.png

视图view.php中显示的是table_2-4中的数据,与table_1相关:

foreach($rows as $row) {
    echo $row['t2_field_1'];
    echo $row['t2_field_2'];
    ...
}

见:Yii2 innerJoin() 和:http://www.yiiframework.com/doc-2.0/yii-db-query.html

它有效,但我不确定它是否是最正确的 Yii2 方式。

我尝试在模型 TableOne 中定义关系:

public function getTableTwoRecords()
{
    return $this->hasMany(TableTwo::className(), ['t1_id' => 'id']);
}
public function getTableThreeRecords()
{
    return $this->hasMany(TableThree::className(), ['id' => 't3_id'])
    ->via('tableTwoRecords');
}
public function getTableFourRecords()
{
    return $this->hasMany(TableFour::className(), ['id' => 't4_id'])
    ->via('tableThreeRecords');
}

然后在控制器TableOneController中加入记录:

$records = TableOne::find()
    ->innerJoinWith(['tableTwoRecords'])
    ->innerJoinWith(['tableThreeRecords'])
    ->innerJoinWith(['tableFourRecords'])
    ->all(); 

但它不起作用。如果我只加入前三个表,那么它可以工作。如果我添加第四个表,则会收到以下错误消息:“获取未知属性:frontend\models\TableOne::t3_id”

如果我以这种方式更改函数 getTableFourRecords():

public function getTableFourRecords()
{
    return $this->hasOne(TableThree::className(), ['t4_id' => 'id']);
}

然后我收到此错误消息:“SQLSTATE[42S22]: Column not found: 1054 Unknown column 'table_4.t4_id' in 'on clause' 正在执行的 SQL 是: SELECT table_1.* FROM table_1 INNER JOIN table_2 ON table_1.id = table_2.t1_id INNER JOIN table_3 ON t3_id7@. = table_3.id INNER JOIN table_4 ON table_1.id = table_4.t4_id"

【问题讨论】:

  • 我想你这里有一个类型:['id', 't3_id']) 它应该是['id' => 't3_id']
  • @TouqeerShafi 谢谢。看起来我一直有错字。我必须是盲人。我现在再次尝试一切。
  • @TouqeerShafi 我需要一些时间来测试它,因为真正的数据库方案看起来完全不同......它现在对前三个表工作正常。我不知道,如何将第四个表正确添加到模型中。我编辑了这个问题。您可以看到我现在收到的错误。

标签: yii2 inner-join


【解决方案1】:

您应该必须在关系中定义键值对,例如:

class Customer extends ActiveRecord
{
    public function getOrders()
    {
        return $this->hasMany(Order::className(), ['customer_id' => 'id']); // Always KEY => VALUE pair this relation relate to hasMany relation
    }
}

class Order extends ActiveRecord
{
    public function getCustomer()
    {
        return $this->hasOne(Customer::className(), ['id' => 'customer_id']);
// Always KEY => VALUE pair this relation relate to hasOne relation
        }
    }

现在在你的第四关系中使用:

public function getTableFourRecords()
{
    return $this->hasOne(TableThree::className(), ['id' => 't4_id']);
}

您可以阅读更多关于 ActiveRecord here

【讨论】:

【解决方案2】:

基于softark的answer最简单的解决方案如下所示:

模型表一:

public function getTableTwoRecords()
    {
        return $this->hasMany(TableTwo::className(), ['t1_id' => 'id']);
    }

模型表二:

public function getTableThreeRecord()
    {
        return $this->hasOne(TableThree::className(), ['id' => 't3_id']);
    }

模型表三:

public function getTableFourRecord()
{
    return $this->hasOne(TableFour::className(), ['id' => 't4_id']);
}

控制器 TableOneController:

public function actionView($id)
{
    return $this->render('view', [
         'model' => $this->findModel($id),
    ]);
}

view table-one/view.php:

foreach ($model->tableTwoRecords as $record) {
    echo ' Table 2 >> ';
    echo ' ID: ' . $record->id;
    echo ' T1 ID: ' . $record->t1_id;
    echo ' T3 ID: ' . $record->t3_id;
    echo ' Table 3 >> ';
    echo ' ID: ' . $record->tableThreeRecord->id;
    echo ' T4 ID: ' . $record->tableThreeRecord->t4_id;
    echo ' Table 4 >> ';
    echo ' ID: ' . $record->tableThreeRecord->tableFourRecord->id;
    echo ' <br>';
}

基于 GridView 的解决方案也是可能的。

模型表二:

public function getTableOneRecord()
{
    return $this->hasOne(TableOne::className(), ['id' => 't1_id']);
}
public function getTableThreeRecord()
{
    return $this->hasOne(TableThree::className(), ['id' => 't3_id']);
}
public function getTableFourRecord()
{
    return $this->hasOne(TableFour::className(), ['id' => 't4_id'])
        ->via('tableThreeRecord');
}

编辑了 TableOneController 中的函数 actionView,它是用 Gii 为模型 TableTwo 生成的:

use app\models\TableTwo;
use app\models\TableTwoSearch;
...
public function actionView($id)
{
    $searchModel = new TableTwoSearch([
        't1_id' => $id, // the data have to be filtered by the id of the displayed record
    ]);
    $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

    return $this->render('view', [
         'model' => $this->findModel($id),
         'searchModel' => $searchModel,
         'dataProvider' => $dataProvider,
    ]);
}

还有views/table-one/view.php:

echo GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => [
     'id',
     't1_id',
     'tableOneRecord.id',
     't3_id',
     'tableThreeRecord.id',
     'tableThreeRecord.t4_id',
     'tableFourRecord.id',
    ],
]);

请参阅code on Github

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-21
    • 2017-10-24
    • 1970-01-01
    • 1970-01-01
    • 2020-11-21
    • 1970-01-01
    相关资源
    最近更新 更多