Laravel 5.5 Eloquent ORM - 关联关系

简介

数据表经常要与其它表做关联,比如一篇博客文章可能有很多评论,或者一个订单会被关联到下单用户。

Eloquent 让组织和处理这些关联关系变得简单,并且支持多种不同类型的关联关系:

  • 一对一
  • 一对多
  • 多对多
  • 远层一对多
  • 多态关联
  • 多对多的多态关联

定义关联关系

关联关系以 Eloquent 模型类方法的方式定义。

和 Eloquent 模型本身一样,关联关系也是强大的查询构建器,定义关联关系为方法可以提供功能强大的方法链和查询能力。

例如,我们可以添加更多约束条件到 post 关联关系:

$user->posts()->where('active', 1)->get();

在深入使用关联关系之前,让我们先学习如何定义每种关联关系。

一对一

一对一关联是一个最简单的关联关系。

例如,一个 User 模型有一个与之关联的 Phone 模型。

要定义这种关联关系,我们需要将 phone 方法置于User 模型中,phone 方法调用 Illuminate\Database\Eloquent\Concerns\HasRelationships trait 中的 hasOne 方法并返回其结果。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model{
    /**
     * 获取关联到用户的手机
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

传递给 hasOne 方法的第一个参数是关联模型的名称,关联关系被定义后,我们可以使用 Eloquent 的动态属性获取关联记录。

动态属性允许我们访问关联方法,就像它们是定义在模型上的属性一样:

$phone = User::find(1)->phone;

Eloquent 默认关联关系的外键基于模型名称,在本例中,Phone 模型默认有一个 user_id 外键,如果你希望覆盖这种约定,可以传递第二个参数到 hasOne 方法:

return $this->hasOne('App\Phone', 'foreign_key');

此外,Eloquent 假设外键应该在父级上有一个与之匹配的 id(或者自定义 $primaryKey),换句话说,Eloquent 将会通过 user 表的 id 值去 phone 表中查询 user_id 与之匹配的 Phone 记录。如果你想要关联关系使用其他值而不是 id,可以传递第三个参数到hasOne 来指定自定义的主键:

return $this->hasOne('App\Phone', 'foreign_key', 'local_key');

我们通过传递完整参数改写上述示例代码:

return $this->hasOne('App\Phone', 'user_id', 'id');  

定义相对的关联

我们可以从 User 中访问 Phone 模型,相应地,也可以在 Phone 模型中定义关联关系从而让我们可以拥有该手机的 User。

可以使用 belongsTo 方法定义与 hasOne 关联关系相对的关联:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Phone extends Model{
    /**
     * 获取拥有该手机的用户
     */
    public function user()
    {
        return $this->belongsTo('App\User');
    }
}

Eloquent 默认将会尝试通过 Phone 模型的 user_id 去 User 模型查找与之匹配的记录。

Eloquent 通过在关联关系方法名后加 _id 后缀来生成默认的外键名。不过,如果 Phone 模型上的外键不是 user_id,也可以将自定义的键名作为第二个参数传递到 belongsTo 方法:

return $this->belongsTo('App\User', 'foreign_key');

如果父模型不使用 id 作为主键,或者你希望使用别的数据列来连接子模型,可以将父表自定义键作为第三个参数传递给 belongsTo 方法:

return $this->belongsTo('App\User', 'foreign_key', 'other_key');

同样,我们通过传递完整的参数来改写上述示例代码:

return $this->belongsTo('App\User', 'user_id', 'id');

默认模型

belongsTo 关联关系允许你在给定关联关系为 null 的情况下,定义一个默认的返回模型,我们将这种模式称之为空对象模式,使用这种模式的好处是不用在代码中编写大量的判断检查逻辑。

在下面的例子中,user 关联将会在没有用户与文章关联的情况下返回一个空的 App\User 模型:

/**
 * 获取文章作者
 */
public function user()
{
    return $this->belongsTo('App\User')->withDefault();
}

要通过属性填充默认的模型,可以传递数据或闭包到 withDefault 方法:

/**
 * 获取文章作者
 */
public function user()
{
    return $this->belongsTo('App\User')->withDefault([
        'name' => 'Guest Author',
    ]);
}

/**
 * 获取文章作者
 */
public function user()
{
    return $this->belongsTo('App\User')->withDefault(function ($user) {
        $user->name = 'Guest Author';
    });
}

一对多

“一对多”关联是用于定义单个模型拥有多个其它模型的关联关系。

例如,一篇博客文章拥有多条评论,和其他关联关系一样,一对多关联通过在 Eloquent 模型中定义方法来定义:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model{
    /**
     * 获取博客文章的评论
     */
    public function comments()
    {
         return $this->hasMany('App\Comment');
    }
}

记住,Eloquent 会自动判断 Comment 模型的外键,为方便起见,Eloquent 将拥有者模型名称加上 _id 后缀作为外键。因此,在本例中,Eloquent 假设 Comment 模型上的外键是 post_id。

关联关系被定义后,我们就可以通过访问 comments 属性来访问评论集合。由于 Eloquent 提供了“动态属性”,我们可以像访问模型的属性一样访问关联方法:

$comments = App\Post::find(1)->comments;

foreach ($comments as $comment) {
    //
}

当然,由于所有关联同时也是查询构建器,我们可以添加更多的条件约束到通过调用 comments 方法获取到的评论上:

$comments = App\Post::find(1)->comments()->where('title', 'foo')->first();

和 hasOne 方法一样,你还可以通过传递额外参数到 hasMany 方法来重新设置外键和本地主键:

return $this->hasMany('App\Comment', 'foreign_key');
return $this->hasMany('App\Comment', 'foreign_key', 'local_key');

// 在本例中,传递完整参数代码如下
return $this->hasMany('App\Comment', 'post_id', 'id');

一对多(逆向)

现在我们可以访问文章的所有评论了,接下来让我们定义一个关联关系允许通过评论访问所属文章。

要定义与 hasMany 相对的关联关系,需要在子模型中定义一个关联方法去调用 belongsTo 方法:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model{
    /**
     * 获取评论对应的博客文章
     */
    public function post()
    {
        return $this->belongsTo('App\Post');
    }
}

关联关系定义好之后,我们就可以通过访问动态属性 post 来获取某条 Comment 对应的 Post:

$comment = App\Comment::fin
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值