6把刀 2016-02-27 23:11:04 6362次浏览 7条评论 10 1 0
class Customer extends \yii\db\ActiveRecord
{
    public function getOrders()
    {
        // 客户和订单通过 Order.customer_id -> id 关联建立一对多关系
        return $this->hasMany(Order::className(), ['customer_id' => 'id']);
    }
}

class Order extends \yii\db\ActiveRecord
{
    // 订单和客户通过 Customer.id -> customer_id 关联建立一对一关系
    public function getCustomer()
    {
        return $this->hasOne(Customer::className(), ['id' => 'customer_id']);
    }
}

两个ActiveRecord 分别是 Customer、Order表(下面用A表与B表表示,打字累)
A表有一个一对多B表的关系,反之B表对应一个对一关系,

创建时
控制器定义两个

$A = new Customer();
$B = new Order();
if($A->load(\Yii::$app->request->post()) && $B->load(\Yii::$app->request->post()){
   $A->save();
   $A->link('orders', $B);
}
//这下面要注意下要返回两个对象
return $this->render('create', [
    'A' => $A,
    'B' => $B,
]);

因为你要显示相应的field字duan,
上面意思定义两个模型实例,分别加载post数据,这里的load当没有指定第一个参数时,他会自动载入$this
也就相当于第一个$A->load(\Yii::$app->request->post());等同于$A->load(\Yii::$app->request->post(),'Customet');去看下base\model的load方法就知道了

这里要注意的是View页面

<?= $form->field($a,'customer_id')->textInput()?>;//这是A表的字duan,
<?= $form->field($B,'id')->textInput()?>;//这是B表的字duan,

这样他才会找到相应的模型
创建结束

更新多模型

$A = Customer::findModel($id);
$B = $A->orders; //这里去看手册,这里当用属性方式返回时是取得成品数组,如果用方法,那得$A->getOrders()->all();因为方法得到的是一个对象,
//上面的代码等同于
$A = Customer::find()->with('orders')->where('id=:id', [':id' => $id])->one();
//这样的话$A->orders == $B;

//之后跟上面创建一样
if($A->load(\Yii::$app->request->post()) && $B->load(\Yii::$app->request->post()){
   $A->save();
   $B->save();
}

//另一种写法
if($A->load(\Yii::$app->request->post()) && $A->orders->load(\Yii::$app->request->post()){
   $A->save();
   $A->orders->save();
}

更新结束

删除多表
$A = Customer::findModel($id);
$B = $A->orders;
if($A->delete() && $B->delete(){
//删除两张表的数据
}

好了,结束了,给新手吧。第一次发文章

觉得很赞
  • 评论于 2016-03-02 17:43 举报

    看了半天还是没看懂,太笨

    1 条回复
    评论于 2016-03-03 08:46 回复

    比如一个文章表,一个是文章的附加表,这个就是这个文章的添加,修改,删除。

  • 评论于 2016-03-03 15:55 举报

    loadMultiple 和 validateMultiple

    1 条回复
    评论于 2016-03-04 11:48 回复

    你这个是多记录,并不是多表

  • 评论于 2016-03-25 15:20 举报
    1 条回复
    评论于 2016-09-02 12:20 回复

    这个是一个controller使用多个model 的示例吗? 不是一个model中包含多个表吧。

  • 评论于 2016-07-01 20:10 举报

    请教:你上面的添加例子是 一条Customer一条Order,请问一条Customer多条Order怎么实现? Order用数组传递??

    例如新增 一个Custer多个Order

    1 条回复
    评论于 2016-07-02 09:45 回复

    一对多,一对一其实就是他数据为one或all的区别,就像活动记录的one 与 all
    而活动记录里的getOrders与getCustomers相当于是活动记录的一个子方法,当你调用他后,你再用 with,他会再去执行一次这个SQL,把这个数据以数组的方式,增加到先前的SQL得到的数据上。这就拼接起来了两个表的数据。
    同理,当你三表四表,都是一样的逻辑。
    我表达不出来。不知道我说的你理解了没

  • 评论于 2016-08-20 15:36 举报

    有个问题 假如用户 id为1 的订单为空 那么Customer::findModel($id)->orders 也为空,view层该如何处理这种空?

    1 条回复
    评论于 2016-08-22 12:54 回复

    isset这个来判断对象是否为空,怎么处理,看你业务逻辑

  • 评论于 2017-05-29 18:14 举报

    楼主好,首先感谢您写出这样的教程。我最近也在为这样的问题烦恼!
    按照以前的习惯,我会将多个表的操作封装在一个主model里。这样控制器不需要额外的逻辑判断。
    楼主这样写,是不是在某些情况下,会吧逻辑写在控制器里呢?比如说,根据返回值,判断是否向某个表里插入扩展数据!!

    5 条回复
    评论于 2017-06-01 09:29 回复

    恩,可以这样,就是可以重写model 的save方法,那以后在外面控制器里只要$a->save他就会把B也存了。
    代码这东西,就是结构的拼装,积木块一样,只要你能想,都能有办法实现。只是好与更好的区别。没有最优,只有更优

    评论于 2017-06-06 17:45 回复

    呵呵,感觉在控制器里写一写逻辑反倒更容易一些!

    评论于 2017-06-07 11:15 回复

    看理解了,我更喜欢把控制器看成是路由。他只负责引路,而处理的其实是数据模型该做的事。
    比如vue2,ng2前端框架

    评论于 2017-06-07 13:00 回复

    直接重写save会不会有问题?

    评论于 2017-06-08 15:02 回复

    怎么会有问题,不会有问题的。当然save他本身提供了几个事件给你,你可以添加行为触发事件,就不用重写save了。反正条条大路通罗马

  • 评论于 2017-10-15 10:47 举报

    hasMany 为什么返回数组内嵌对象啊?$B->delete()报function delete() on array错了,是什么原因?检查了没有用asArray转换

您需要登录后才可以评论。登录 | 立即注册