Laravel Eloquent ORM 教程:Eloquent 之旅第二部分
了解 Eloquent 关联
再次欢迎。这个帖子我将深入 Laravel Eloquent 关联,如果你错过了上一篇文章,可以在这篇文章的底部找到链接。
我们都知道数据库表经常和另一个表关联,以博客平台为例,用户表会与帖子、评论和回复表关联,而帖子表会评价评论表,回复则与评论表关联。 Eloquent 打包了底层结构,得以让我们管理数据库表之间的关系,让表之间的查询变得简单又灵活。
Eloquent 支持多种关联关系,包括:
- 一对一
- 一对多
- 多对多
- 远程一对一
- 远程一对多
- 一对一(多态)
- 一对多(多态)
- 多对多(多态)
Eloquent 关联关系由模型类中的方法定义。方法名由你来定,但要确保给一个能解释关联关系的名字。
一对一
一对一关系是一种通过单个数据将一个模型与另一个模型关联的关系。假设我们有一个配置文件模型,它将在我们的数据库中保存关于用户的配置文件信息。我们希望我们的用户只有一个配置文件,而一个配置文件应该属于一个用户。这种关系是一种一对一
关系,为了实现这种关系,我们希望我们的配置文件表通过添加一列来创建此连接,而使用外键
约束与我们的用户表建立连接。
Sample Profile table
id | user_id | address |
---|---|---|
1 | 1 | 20 Markson St. |
$table->unsignedInteger('user_id')
$table->foriegnKey('user_id')->references('id')->on('users')->onDelete('cascade')
把以上内容添加到配置文件表迁移中,laravel就可以帮在模型之间我们创建好关联关系。
我们现在可以定义模型之间的关系。因为外键在Profile模型上,现在,我们可以使用Eloquent的hasOne()
方法,让它将我们的用户模型绑定到用户表中的用户具有配置文件的配置文件模型,方法如下:
/**
*Returns an Eloquent relationship
**/
public function profile()
{
return $this->hasOne(Profile::class);
}
profile表中有一个user_id
列,但是在suitation中,你需要有一个不同的列名来表示我们的users表的外键
id | custom_user_id |
address |
---|---|---|
1 | 1 | 20 Markson St. |
指定hasOne()
的第二个参数就可以了
return $this->hasOne(Profile::class, 'custom_user_id');
Eloquent 预计我们的user
表上主键是id
,但是有时候,我们的主键并不是id
用户示例表
user_id |
name |
---|---|
1 | Samfield Hawb |
我们可以传递第三个参数
return $this->hasOne(Profile::class, 'custom_user_id','user_id');
我们已经在 User 模型和 Profile 模型之间建立了关系,现在让我们使用 Eloquent 的belongsTo()
方法创建反向关联。我们将在 Profile 模型类中定义反向关联;
/**
*Returns an Eloquent Relationship
*/
public function user()
{
return $this->belongsTo(User::class);
}
Eloquent 会尝试将profile
表上的user_id
与user
表上的id
匹配,在以下这种情况下,profile
表上的外键具有不同的列名
id | custom_user_id |
address |
---|---|---|
1 | 1 | 20 Markson St. |
通过提供 belongsTo()
方法的第二个参数来指定外键列名。
return $this->belongsTo(User::class, 'custom_user_id');
在上面的情况下,Eloquent ORM 使用的是默认主键 id
, 但是很多情况下我们的主键并非 id
,例如下面这个:
user_id |
name |
---|---|
1 | Samfield Hawb |
相应的,Eloquent ORM 提供了第三个参数,通过第三个参数,我们就可以自定义我们的主键列了。
return $this->belongsTo(User::class, 'custom_user_id','user_id');
建立完成模型关联,我们就可以在我们程序中使用他们了,下面是几个使用的例子:
$user = \App\User::find(1);
$user->profile;//可以直接在 user 获取相关联的 profile 信息了。
//同样的适用于反向的关联
$profile = \App\Profile::find(1);
$profile->user; //获取 profile 所属 user
$profile->user->name; //获取user name属性
一对多关联
所谓的一对多就是一个记录对应多条记录的情况。举个例子,博客系统中一个用户可能会发布很多文章,相应的一个用户也可能给多个文章评论,回复等。Eloquent Orm 提供了 hasMany()
方法就是为了处理这种情况。下面就让我们看看如何为我们的 posts 表创建一对多关联吧!
posts 表结构如下:
id | title | content | user_id |
---|---|---|---|
1 | Mastering laravel Eloquent ORM | content | 1 |
public function posts()
{
return $this->hasMany(Post::class);
}
Eloquent 会默认使用 posts 表中的 user_id
字段做外键,大多数时候,我们表中可能并不是这个字段名。
id | title | content | custom_user_id |
---|---|---|---|
1 | Mastering laravel Eloquent ORM | content | 1 |
这时候 hasMany()
方法的第二个参数就派上用场了,
return $this->hasMany(Post::class,'custom_user_id');
同样 Eloquent Orm 默认使用User
标的 id
作为关联主键,如果我们字段并不相同,我们可以通过你指定 hasMany()
方法第三个参数来自定义关联主键。
return $this->hasMany(Post::class,'custom_user_id','user_id')
我们已经将我们的 User 与 Post 做好了正向关联。现在我们通过 belongsTo()
在 Post中创建相应的反向关联。
public function user()
{
return $this->belongsTo(User::class);
}
从上文中的经验来看,这里的 belongsTo()
也是通过第二个参数自定义关联外键。
return $this->belongsTo(User::class, 'custom_user_id');
同样的这也适用于第三个参数,自定义关联主键。
return $this->belongsTo(User::class, 'custom_user_id','user_id');
通过现在的设置, 我们现在可以用 eloquent 查询模型之间的数据。 让我们从数据库中获取id
为 1的用户的所有文章;
$user = \App\User::findOrFail(1); //我们查询的用户
//打印用户的所有文章的标题
foreach ($user->posts as $post)
{
echo $post->title;
}
我们已经看到,通过模型关联,我们可以轻松的从eloquent中查询所有的文章,我们可以创建一个文章绑定到特定的用户;
$user = \App\User::find(1);
$user->posts()->create([
//我们提供所有代表key跟value的列名
// 'key' => 'value'
]);
通过上面的代码实例, Eloquent会自动从$user对象中提取 user_id
来创建文章。同样, 用 createMany()
方法,我们可以一次性向用户创建很多文章。 我们稍后在讨论这个。
假设我们想获取该文章的用户名, 我们也可以从关系模型中轻松实现;
$post = \App\Post::find(1);
echo $post->user->name;
多对多关联
当我们构建 web 程序的时候, 可能会遇到这样的需求,我们为博客系统引入角色系统而实现权限控制,这时候一个用户可以对应多个角色,一个角色可能有多个用户,像这种多对多的关系,我们需要额外创建一个表来存储关联信息,下面我们创建 create_role_user_table
迁移。
$ php artisan make:migration create_role_user_table --table=role_user
在迁移文件up 方法中,我们加入以下代码:
$table->unsignedInteger('user_id');
$table->unsignedInteger('role_id');
//外键关联
$table->foriegnKey('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foriegnKey('role_id')->references('id')->on('roles')->onDelete('cascade')
Eloquent ORM 可以通过这两列构建我们需要的数据。
下面是以下简单的 role_user 表数据
user_id | role_id |
---|---|
1 | 1 |
1 | 4 |
1 | 3 |
2 | 4 |
现在让我们看一下他是如给 id 1
的用户赋值 ids 1, 4, 3
的角色的:
只要通过 Eloquent ORM 提供的belongsToMany()
方法我们可以很简单的将用户和角色进行关联。
public function roles()
{
return $this->belongsToMany(Role::class);
}
Eloquent 的 belongsToMany() 默认会通过将两个表名使用下划线连接( role_user
)来作为关联表的名称,但是很多时候我们的关联表可能不会这样命名。 这时候,我们可以通过第二个参数来指定使用哪个表作为关联表。
return $this->belongsToMany(Role::class,'custom_role_user');
当然,我们也可以通过第二个第三个参数来自定义关联表所使用的 key。
return $this->belongsToMany(Role::class,'custom_role_user','custom_user_id','custom_role_id');
我们也可以在 role 表创建他的逆关联,这样可以方便我们查询角色下的所有用户。
public function users()
{
return $this->belongsToMany(User::class);
}
关联定义好了,我们就可以使用 Eloquent ORM 来获取关联数据了。
$user = \App\User::find(1);
foreach ($user->roles as $role)
{
echo $role->name
}
$role = \App\Role::find(1);
foreach($role->users as $user)
{
echo $user->name;
}
我们可以使用关联模型和Model里面的attach()
方法为用户分配角色
$user = \App\User::find(1);
$user->roles()->attach(1); //给用户分配ID=1的角色
$user->roles()->attach([2,3,4]); //给用户分配ID为2,3,4的角色
还可以使用 Model 的detach()
方法从用户删除角色;
$user = \App\User::find(1);
$user->roles()->detach(1); //删除ID为1的用户角色
$user->roles()->detach([2,3,4]); //删除ID为2,3,4的用户角色
结论
目前为止,我们已经介绍了eloquent
的 一对一
, 一对多
, 和 多对多
的模型关联。 在下章中,我们将研究其他类型,谢谢关注.
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。