定义
- 模型 用对象表示的表实例,负责与数据库的交互逻辑构建
- 关联模型 要连接到的最终模型
- 关联方法 返回一个关联关系的方法
- 关联属性 $with属性 由关联方法名组成的数组,通常用于渴求式加载
- 连接表 又称中间表,通常用于多对多关系
- 主键 模型的唯一标识符
- 外键 模型对外的通路
- 正向 模型主键匹配关联模型外键
- 反向 模型外键匹配关键模型主键
- 父级模型 拥有下属分支的模型,典型的一对多关系,一则为父级模型
- 子级模型 作为某一模型的后继模型,该模型对象对前驱模型有依赖
- 默认模型
关联关系
一对一 (正向 A->B)
hasOne('App\Phone','foreign_key','local_key')
hasOne 方法的第一个参数 是最终想到达的关联模型的类名,
Eloquent 会基于当前模型名+_id决定关联模型外键名称。
第三个参数,为当前模型的非id以外的自定义关联外键名一对一(反向 B->A)
belongsTo('App\User', 'foreign_key', 'other_key')
第一个参数 要访问的模型类名,俗称关联模型
第二个参数,默认关联方法名+_id为模型的外键名
第三个参数,指定父级数据表自定义键 父级模型没有使用id为主键,或者希望使用不同的字段来连接子模型默认模型
*空对象模式,传递数组或闭包给withDefault方法belongsTo('App\User')->withDefault(); belongsTo('App\User')->withDefault(['name' => '游客',]); belongsTo('App\User')->withDefault(function($user){$user->name = '游客'});
一对多(正向)
Eloquent 使用父级模型名的「snake case」形式、加上 _id 后缀名作为外键字段
所有的关联还可以作为查询语句构造器使用, 可通过传递额外参数来覆盖默认使用的外键与本地键。
hasMany(‘App\Comment’)
hasMany(‘App\Comment’, ‘foreign_key’)
hasMany(‘App\Comment’, ‘foreign_key’, ‘local_key’)反向关联
获得一篇文章的所有评论,接着再定义一个通过评论获得所属文章的关联
hasMany 关联的反向关联,在子级模型中使用 belongsTo 方法定义//comment.php //Get the post that owns the comment. public function post() { return $this->belongsTo('App\Post'); }
示例: 父级模型,子级模型,外键,主键
上述默认,子级模型comment的外键是post+_id (关联名+_id),父级模型post使用id作为主键多对多(连接表)
users roles role_user
belongsToMany('App\Role', 'role_user', 'user_id', 'role_id')
第一个参数 目标关联模型类名
第二个参数连接表名 由关联的两个模型名按照字母顺序确定
第三个参数 定义此关联的模型在连接表里的外键名
第四个参数 另一个模型在连接表里的外键名定义反向关联
定义多对多关联的反向关联,在对方模型里再次调用 belongsToMany 方法即可。获取中间表字段
每个 Role 模型对象,代表中间表的一个模型对象
默认情况下,pivot
对象只包含两个关联模型的键。belongsToMany('App\Role')->withPivot('column1', 'column2') belongsToMany('App\Role')->withTimestamps() belongsToMany('App\Podcast')->as('subscription') ->withTimestamps() //自定义 pivot 属性名称
关联操作
一对多 belongsTo关联
注意需要使用save方法持久化存储
associate 方法在子模型中设置外键
dissociate 方法 当移除 belongsTo 关联时, 将关联外键设置为 null:$account = App\Account::find(10); $user->account()->associate($account); $user->save(); $user->account()->dissociate(); $user->save();
多对多关联 belongsToMany 中间表
允许传递一个ID数组
attach 向中间表插入一条记录
detach 移除多对多关联记录$user = App\User::find(1); $user->roles()->attach($roleId); // 添加附加数据 $user->roles()->attach($roleId, ['expires' => $expires]); // 移除用户的一个角色... $user->roles()->detach($roleId); // 移除用户的所有角色... $user->roles()->detach(); $user = App\User::find(1); $user->roles()->detach([1, 2, 3]); $user->roles()->attach([ 1 => ['expires' => $expires], 2 => ['expires' => $expires] ]);
同步关联
sync
所有未在 ID 数组中的记录都将会被移除$user->roles()->sync([1, 2, 3]); //传递额外数据 $user->roles()->sync([1 => ['expires' => true], 2, 3]); //不移除现有的 ID $user->roles()->syncWithoutDetaching([1, 2, 3]);
切换关联
toggle
方法用于「切换」给定 ID 数组的附加状态。$user->roles()->toggle([1, 2, 3]);
在中间表上保存额外的数据
当处理多对多关联时,save 方法接收一个额外的数据数组作为第二个参数`App\User::find(1)->roles()->save($role, ['expires' => $expires]);`
更新中间表记录
updateExistingPivot
此方法接收中间表的外键与要更新的数据数组进行更新$user = App\User::find(1); $user->roles()->updateExistingPivot($roleId, $attributes);
更新父级时间戳
在子模型加一个包含关联名称的 touches
当一个模型属 belongsTo 或者 belongsToMany 另一个模型时namespace App; use Illuminate\Database\Eloquent\Model; class Comment extends Model { /** * 要触发的所有关联关系。 * * @var array */ protected $touches = ['post']; /** * 评论所属文章。 */ public function post() { return $this->belongsTo('App\Post'); } }
使用场景
更新子模型导致更新父模型时间戳,在子模型加一个包含关联名称的 touches 属性即可。
当 Comment 模型被更新时,您要自动「触发」父级 Post 模型的 updated_at 时间戳的更新。特例
通常多对多形式 A->B->C
但也有 A->B->A 粉丝与粉主
更有 A<->A 多态‘中间表’维护在单张表内