一.准备
1.SQL
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `phone`;
CREATE TABLE `phone` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`url` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
`user_id` int(10) NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 12 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;
INSERT INTO `phone` VALUES (1, 'www.baidu.com1', 1);
INSERT INTO `phone` VALUES (2, 'www.baidu.com2', 1);
INSERT INTO `phone` VALUES (3, 'www.baidu.com3', 2);
INSERT INTO `phone` VALUES (4, 'www.baidu.com4', 2);
INSERT INTO `phone` VALUES (5, 'www.baidu.com5', 3);
INSERT INTO `phone` VALUES (6, 'www.baidu.com6', 4);
INSERT INTO `phone` VALUES (7, 'www.baidu.com7', 5);
INSERT INTO `phone` VALUES (8, 'www.baidu.com8', 3);
INSERT INTO `phone` VALUES (9, 'www.baidu.com9', 4);
INSERT INTO `phone` VALUES (10, 'www.baidu.com10', 5);
INSERT INTO `phone` VALUES (11, 'www.baidu.com11', 6);
SET FOREIGN_KEY_CHECKS = 1;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`email` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`password` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`remember_token` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `users_email_unique`(`email`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 51 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES (1, 'Freddy Stokes DDS', 'jeffrey38@gmail.com', 'LG1yn\"', '6bca2488-cb0f-315b-8cea-09b1e76aea3c', '2018-07-26 02:57:50', '2018-07-26 02:57:50');
INSERT INTO `users` VALUES (2, 'Stefanie Lang', 'kellen49@hotmail.com', 'aO9+|gvmx3A', 'd7ee4f80-35b4-3424-bbdc-afce5138f41c', '2018-07-26 02:57:50', '2018-07-26 02:57:50');
INSERT INTO `users` VALUES (3, 'Mr. Janick Lubowitz', 'gnienow@gmail.com', '6Q#\'.[;XeG]l_', '2d213e3c-bc4c-30bd-ac8f-96059f12064b', '2018-07-26 02:57:50', '2018-07-26 02:57:50');
INSERT INTO `users` VALUES (4, 'Gardner Langosh', 'beer.barrett@gmail.com', '[lmO_oE_oXGAe2', 'fa2b8fe9-e509-340b-8eb6-5e92621bcfa6', '2018-07-26 02:57:50', '2018-07-26 02:57:50');
INSERT INTO `users` VALUES (5, 'Kennedi Torp', 'xkilback@hotmail.com', 'q$!9K,*G-E-C#>v', '978cb679-c5f3-3d03-a8fe-f410fcb4d2c7', '2018-07-26 02:57:50', '2018-07-26 02:57:50');
INSERT INTO `users` VALUES (6, 'Dr. Amari Sauer', 'buddy.jakubowski@rath.com', 'OdH#%P', 'c6a5b8ba-148d-30f0-8fc1-f92e9537f3ac', '2018-07-26 02:57:50', '2018-07-26 02:57:50');
INSERT INTO `users` VALUES (7, 'Dr. Kathlyn Watsica', 'wilfredo64@bartoletti.net', ')<bdWYr:;^YI&s\'', '2d5262f6-7743-30c9-b210-c4ad9e93d288', '2018-07-26 02:57:50', '2018-07-26 02:57:50');
INSERT INTO `users` VALUES (8, 'Elnora Gaylord', 'ufahey@hotmail.com', '*%[J`O', '9d05dc9b-c482-3b9b-978c-dade643d5f5e', '2018-07-26 02:57:50', '2018-07-26 02:57:50');
INSERT INTO `users` VALUES (9, 'Jessyca Klocko DDS', 'dianna.kerluke@runte.com', '%`okm%^tYj^', '9a135dee-981f-35d7-95a2-810175f81014', '2018-07-26 02:57:50', '2018-07-26 02:57:50');
INSERT INTO `users` VALUES (10, 'Mrs. Kaylee Beer', 'yhackett@yahoo.com', 'FR\'=KEPu\\X`y;!gLL', '251f997f-16a5-34dd-a112-1519d1550b55', '2018-07-26 02:57:50', '2018-07-26 02:57:50');
SET FOREIGN_KEY_CHECKS = 1;
2.模型
// UserModel模型
class UserModel extends Model
{
protected $table = 'users';
}
// PhoneModel模型
class PhoneModel extends Model
{
protected $table = 'phone';
}
二.一对一
1.正向关联
// UserModel模型
class UserModel extends Model
{
protected $table = 'users';
public function phone()
{
return $this->hasOne('App\PhoneModel');
// 报错
// SQL: select * from `phone` where `phone`.`user_model_id` = 1 and `phone`.`user_model_id` is not null limit 1
}
public function phone()
{
# 它会自动假设 Phone 模型拥有 user_id 外键。
# 如果你想要重写这个约定,则可以传入第二个参数到 hasOne 方法里。
return $this->hasOne('App\PhoneModel', 'user_id');
}
public function phone()
{
# Eloquent 假设外键会和上层模型的 id 字段(或者自定义的 $primaryKey)的值相匹配。
# 否则,请
return $this->hasOne('App\PhoneModel', 'user_id', 'id');
}
}
// 控制器调用
DB::connection()->enableQueryLog(); //打印SQL
$user = UserModel::find(1);
$user->phone;
echo '<pre />';print_r(DB::getQueryLog());
dd($user->toArray());
// 结果
Array
(
[0] => Array
(
[query] => select * from `users` where `users`.`id` = ? limit 1
[bindings] => Array
(
[0] => 1
)
[time] => 1008
)
[1] => Array
(
[query] => select * from `phone` where `phone`.`user_id` = ? and `phone`.`user_id` is not null limit 1
[bindings] => Array
(
[0] => 1
)
[time] => 2
)
)
array:8 [
"id" => 1
"name" => "Freddy Stokes DDS"
"email" => "jeffrey38@gmail.com"
"password" => "LG1yn""
"remember_token" => "6bca2488-cb0f-315b-8cea-09b1e76aea3c"
"created_at" => "2018-07-26 02:57:50"
"updated_at" => "2018-07-26 02:57:50"
"phone" => array:3 [
"id" => 1
"url" => "www.baidu.com1"
"user_id" => 1
]
]
2.反向关联
# class Phone extends Model
public function user() {
return $this->belongsTo('App\User', 'user_id');
// return $this->belongsTo('App\User', 'foreign_key');
// return $this->belongsTo('App\User', 'foreign_key', 'other_key');
}
Array
(
[0] => Array
(
[query] => select * from `phone` where `phone`.`id` = ? limit 1
[bindings] => Array
(
[0] => 1
)
[time] => 1021
)
[1] => Array
(
[query] => select * from `users` where `users`.`id` = ? limit 1
[bindings] => Array
(
[0] => 1
)
[time] => 2
)
)
array:4 [
"id" => 1
"url" => "www.baidu.com1"
"user_id" => 1
"user" => array:7 [
"id" => 1
"name" => "Freddy Stokes DDS"
"email" => "jeffrey38@gmail.com"
"password" => "LG1yn""
"remember_token" => "6bca2488-cb0f-315b-8cea-09b1e76aea3c"
"created_at" => "2018-07-26 02:57:50"
"updated_at" => "2018-07-26 02:57:50"
]
]
三.一对多
1.正向关联
class UserModel extends Model
{
protected $table = 'users';
public function phone()
{
return $this->hasMany('App\PhoneModel', 'user_id');
}
}
// 打印
Array
(
[0] => Array
(
[query] => select * from `users` where `users`.`id` = ? limit 1
[bindings] => Array
(
[0] => 1
)
[time] => 1013
)
[1] => Array
(
[query] => select * from `phone` where `phone`.`user_id` = ? and `phone`.`user_id` is not null
[bindings] => Array
(
[0] => 1
)
[time] => 3
)
)
array:8 [
"id" => 1
"name" => "Freddy Stokes DDS"
"email" => "jeffrey38@gmail.com"
"password" => "LG1yn""
"remember_token" => "6bca2488-cb0f-315b-8cea-09b1e76aea3c"
"created_at" => "2018-07-26 02:57:50"
"updated_at" => "2018-07-26 02:57:50"
"phone" => array:2 [
0 => array:3 [
"id" => 1
"url" => "www.baidu.com1"
"user_id" => 1
]
1 => array:3 [
"id" => 2
"url" => "www.baidu.com2"
"user_id" => 1
]
]
]
2.反向关联
Array
(
[0] => Array
(
[query] => select * from `phone` where `phone`.`id` = ? limit 1
[bindings] => Array
(
[0] => 1
)
[time] => 1031
)
[1] => Array
(
[query] => select * from `users` where `users`.`id` = ? limit 1
[bindings] => Array
(
[0] => 1
)
[time] => 2
)
)
array:4 [
"id" => 1
"url" => "www.baidu.com1"
"user_id" => 1
"user" => array:7 [
"id" => 1
"name" => "Freddy Stokes DDS"
"email" => "jeffrey38@gmail.com"
"password" => "LG1yn""
"remember_token" => "6bca2488-cb0f-315b-8cea-09b1e76aea3c"
"created_at" => "2018-07-26 02:57:50"
"updated_at" => "2018-07-26 02:57:50"
]
]
四.多对多
1.SQL
DROP TABLE IF EXISTS `role_user`;
CREATE TABLE `role_user` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`role_id` int(10) NOT NULL,
`user_id` int(10) NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 5 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Fixed;
-- ----------------------------
-- Records of role_user
-- ----------------------------
INSERT INTO `role_user` VALUES (1, 1, 1);
INSERT INTO `role_user` VALUES (2, 1, 2);
INSERT INTO `role_user` VALUES (3, 2, 1);
INSERT INTO `role_user` VALUES (4, 2, 2);
DROP TABLE IF EXISTS `roles`;
CREATE TABLE `roles` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`role_name` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 4 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of roles
-- ----------------------------
INSERT INTO `roles` VALUES (1, 'guanliyuan');
INSERT INTO `roles` VALUES (2, 'yonghu');
INSERT INTO `roles` VALUES (3, 'huiyuan');
2.模型和调用
// 模型
class UserModel extends Model
{
protected $table = 'users';
public function role()
{
return $this->belongsToMany('App\RoleModel', 'role_user', 'user_id', 'role_id');
}
}
// 调用
DB::connection()->enableQueryLog();
$user = UserModel::find(1)->role;
echo '<pre />';print_r(DB::getQueryLog());
dd($user->toArray());
// 打印
Array
(
[0] => Array
(
[query] => select * from `users` where `users`.`id` = ? limit 1
[bindings] => Array
(
[0] => 1
)
[time] => 1011
)
[1] => Array
(
[query] => select `roles`.*, `role_user`.`user_id` as `pivot_user_id`, `role_user`.`role_id` as `pivot_role_id` from `roles` inner join `role_user` on `roles`.`id` = `role_user`.`role_id` where `role_user`.`user_id` = ?
[bindings] => Array
(
[0] => 1
)
[time] => 2
)
)
array:2 [
0 => array:3 [
"id" => 1
"role_name" => "guanliyuan"
"pivot" => array:2 [
"user_id" => 1
"role_id" => 1
]
]
1 => array:3 [
"id" => 2
"role_name" => "yonghu"
"pivot" => array:2 [
"user_id" => 1
"role_id" => 2
]
]
]
3.反向关联
<?php
# class Role extends Model
public function users() {
return $this->belongsToMany('App\User');
}
4.操作中间表
我们取出的每个 Role 模型对象,都会被自动赋予 pivot 属性。
- 获取中间表字段
# 默认情况下,pivot 对象只提供模型的键。如果你的 pivot 数据表包含了其它的属性,则可以在定义关联方法时指定那些字段:
return $this->belongsToMany('App\Role')->withPivot('id');
Array
(
[0] => Array
(
[query] => select * from `users` where `users`.`id` = ? limit 1
[bindings] => Array
(
[0] => 1
)
[time] => 1016
)
[1] => Array
(
[query] => select `roles`.*, `role_user`.`user_id` as `pivot_user_id`, `role_user`.`role_id` as `pivot_role_id`, `role_user`.`id` as `pivot_id` from `roles` inner join `role_user` on `roles`.`id` = `role_user`.`role_id` where `role_user`.`user_id` = ?
[bindings] => Array
(
[0] => 1
)
[time] => 4
)
)
array:2 [
0 => array:3 [
"id" => 1
"role_name" => "guanliyuan"
"pivot" => array:3 [
"user_id" => 1
"role_id" => 1
"id" => 1
]
]
1 => array:3 [
"id" => 2
"role_name" => "yonghu"
"pivot" => array:3 [
"user_id" => 1
"role_id" => 2
"id" => 3
]
]
]
# 如果你想要中间表自动维护 created_at 和 updated_at 时间戳,可在定义关联方法时加上 withTimestamps 方法:
return $this->belongsToMany('App\Role')->withTimestamps();
- 使用中间表来过滤关联数据
# 你可以使用 wherePivot 和 wherePivotIn 来增加中间件表过滤条件:
return $this->belongsToMany('App\Role')->wherePivot('id', 1);
return $this->belongsToMany('App\Role')->wherePivotIn('id', [1, 2]);
- 重命名 pivot
# 你可以使用 wherePivot 和 wherePivotIn 来增加中间件表过滤条件:
return $this->belongsToMany('App\Podcast')
->as('subscription')
->withTimestamps();
// 使用
$users = User::with('podcasts')->get();
foreach ($users->flatMap->podcasts as $podcast) {
echo $podcast->subscription->created_at;
}
五.关联查询
1.查找关联是否存在
// 获取那些至少拥有一个手机号的人
$user = UserModel::has('phone')->get();
#select * from `users` where exists (select * from `phone` where `users`.`id` = `phone`.`user_id`)
// 获取没有手机号的人
$user = UserModel::doesntHave('phone')->get();
#select * from `users` where not exists (select * from `phone` where `users`.`id` = `phone`.`user_id`)
// 获取所有至少有2个手机号的人
$user = UserModel::has('phone', '>=', 2)->get();
#select * from `users` where (select count(*) from `phone` where `users`.`id` = `phone`.`user_id`) >= 2
# 如果你想要更高级的用法,则可以使用 whereHas 和 orWhereHas 方法
# 在 has 查找里设置「where」条件。
# 此方法可以让你增加自定义条件至关联条件中,例如对评论内容进行检查
$user = UserModel::whereHas('phone', function ($query) {
$query->where('url', 'like', '%2%');
})->get();
$user = UserModel::whereDoesntHave('phone', function ($query) {
$query->where('url', 'like', '%2%');
})->get();
2.关联数据计数
# 如果你想对关联数据进行计数,请使用 withCount 方法,
# 此方法会在你的结果集中增加一个 {relation}_count 字段
$user = UserModel::withCount('phone')->get();
Array
(
[0] => Array
(
[query] => select `users`.*, (select count(*) from `phone` where `users`.`id` = `phone`.`user_id`) as `phone_count` from `users`
[bindings] => Array
(
)
[time] => 1014
)
)
array:10 [
0 => array:8 [
"id" => 1
"name" => "Freddy Stokes DDS"
"email" => "jeffrey38@gmail.com"
"password" => "LG1yn""
"remember_token" => "6bca2488-cb0f-315b-8cea-09b1e76aea3c"
"created_at" => "2018-07-26 02:57:50"
"updated_at" => "2018-07-26 02:57:50"
"phone_count" => 2
]
]
3.预加载 ——- 这个重点
- with
$user = UserModel::with('role')->get();
Array
(
[0] => Array
(
[query] => select * from `users`
[bindings] => Array
(
)
[time] => 1004
)
[1] => Array
(
[query] => select `roles`.*, `role_user`.`user_id` as `pivot_user_id`, `role_user`.`role_id` as `pivot_role_id` from `roles` inner join `role_user` on `roles`.`id` = `role_user`.`role_id` where `role_user`.`user_id` in (?)
[bindings] => Array
(
[0] => 1
)
[time] => 0
)
)
array:10 [
0 => array:8 [
"id" => 1
"name" => "Freddy Stokes DDS"
"email" => "jeffrey38@gmail.com"
"password" => "LG1yn""
"remember_token" => "6bca2488-cb0f-315b-8cea-09b1e76aea3c"
"created_at" => "2018-07-26 02:57:50"
"updated_at" => "2018-07-26 02:57:50"
"role" => array:2 [
0 => array:3 [
"id" => 1
"role_name" => "guanliyuan"
"pivot" => array:2 [
"user_id" => 1
"role_id" => 1
]
]
1 => array:3 [
"id" => 2
"role_name" => "yonghu"
"pivot" => array:2 [
"user_id" => 1
"role_id" => 2
]
]
]
]
]
- 预加载条件限制
$user = UserModel::with(['role'=>function($query){
$query->where('role_name', 'like', '%guanliyuan%');
}])->get();
$user = UserModel::with(['role' => function ($query) {
$query->orderBy('id', 'desc');
}])->get();
Array
(
[0] => Array
(
[query] => select * from `users`
[bindings] => Array
(
)
[time] => 1011
)
[1] => Array
(
[query] => select `roles`.*, `role_user`.`user_id` as `pivot_user_id`, `role_user`.`role_id` as `pivot_role_id` from `roles` inner join `role_user` on `roles`.`id` = `role_user`.`role_id` where `role_user`.`user_id` in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) and `role_name` like ?
[bindings] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
[6] => 7
[7] => 8
[8] => 9
[9] => 10
[10] => %guanliyuan%
)
[time] => 4
)
)
array:10 [
0 => array:8 [
"id" => 1
"name" => "Freddy Stokes DDS"
"email" => "jeffrey38@gmail.com"
"password" => "LG1yn""
"remember_token" => "6bca2488-cb0f-315b-8cea-09b1e76aea3c"
"created_at" => "2018-07-26 02:57:50"
"updated_at" => "2018-07-26 02:57:50"
"role" => array:1 [
0 => array:3 [
"id" => 1
"role_name" => "guanliyuan"
"pivot" => array:2 [
"user_id" => 1
"role_id" => 1
]
]
]
]
1 => array:8 [
"id" => 2
"name" => "Stefanie Lang"
"email" => "kellen49@hotmail.com"
"password" => "aO9+|gvmx3A"
"remember_token" => "d7ee4f80-35b4-3424-bbdc-afce5138f41c"
"created_at" => "2018-07-26 02:57:50"
"updated_at" => "2018-07-26 02:57:50"
"role" => array:1 [
0 => array:3 [
"id" => 1
"role_name" => "guanliyuan"
"pivot" => array:2 [
"user_id" => 2
"role_id" => 1
]
]
]
]
2 => array:8 [
"id" => 3
"name" => "Mr. Janick Lubowitz"
"email" => "gnienow@gmail.com"
"password" => "6Q#'.[;XeG]l_"
"remember_token" => "2d213e3c-bc4c-30bd-ac8f-96059f12064b"
"created_at" => "2018-07-26 02:57:50"
"updated_at" => "2018-07-26 02:57:50"
"role" => []
]
3 => array:8 [
"id" => 4
"name" => "Gardner Langosh"
"email" => "beer.barrett@gmail.com"
"password" => "[lmO_oE_oXGAe2"
"remember_token" => "fa2b8fe9-e509-340b-8eb6-5e92621bcfa6"
"created_at" => "2018-07-26 02:57:50"
"updated_at" => "2018-07-26 02:57:50"
"role" => []
]
]
- 延迟预加载
有时你可能需要在上层模型被获取后才预加载关联。
// 调用
$users = UserModel::all();
$users->load('role');
Array
(
[0] => Array
(
[query] => select * from `users`
[bindings] => Array
(
)
[time] => 1030
)
[1] => Array
(
[query] => select `roles`.*, `role_user`.`user_id` as `pivot_user_id`, `role_user`.`role_id` as `pivot_role_id` from `roles` inner join `role_user` on `roles`.`id` = `role_user`.`role_id` where `role_user`.`user_id` in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
[bindings] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
[6] => 7
[7] => 8
[8] => 9
[9] => 10
)
[time] => 2
)
)
array:10 [
0 => array:8 [
"id" => 1
"name" => "Freddy Stokes DDS"
"email" => "jeffrey38@gmail.com"
"password" => "LG1yn""
"remember_token" => "6bca2488-cb0f-315b-8cea-09b1e76aea3c"
"created_at" => "2018-07-26 02:57:50"
"updated_at" => "2018-07-26 02:57:50"
"role" => array:2 [
0 => array:3 [
"id" => 1
"role_name" => "guanliyuan"
"pivot" => array:2 [
"user_id" => 1
"role_id" => 1
]
]
1 => array:3 [
"id" => 2
"role_name" => "yonghu"
"pivot" => array:2 [
"user_id" => 1
"role_id" => 2
]
]
]
]
1 => array:8 [
"id" => 2
"name" => "Stefanie Lang"
"email" => "kellen49@hotmail.com"
"password" => "aO9+|gvmx3A"
"remember_token" => "d7ee4f80-35b4-3424-bbdc-afce5138f41c"
"created_at" => "2018-07-26 02:57:50"
"updated_at" => "2018-07-26 02:57:50"
"role" => array:2 [
0 => array:3 [
"id" => 1
"role_name" => "guanliyuan"
"pivot" => array:2 [
"user_id" => 2
"role_id" => 1
]
]
1 => array:3 [
"id" => 2
"role_name" => "yonghu"
"pivot" => array:2 [
"user_id" => 2
"role_id" => 2
]
]
]
]
2 => array:8 [
"id" => 3
"name" => "Mr. Janick Lubowitz"
"email" => "gnienow@gmail.com"
"password" => "6Q#'.[;XeG]l_"
"remember_token" => "2d213e3c-bc4c-30bd-ac8f-96059f12064b"
"created_at" => "2018-07-26 02:57:50"
"updated_at" => "2018-07-26 02:57:50"
"role" => []
]