PS:主表主键设为 id,关联主键默认就是 id,可以默认不写; PS:附表的外键设置为 user_id,即:主表名_主键,吻合可默认不写
//正相关联 User.php,一对一关联Profile表
namespace App\Http\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function profile(){
//参数1或:'App\Http\Models\Profile' //参数2:默认为user_id,如不是需要指明
return $this->hasOne(Profile::class,'user_id','id');
}
}
//控制器下
$profiles = User::find(19)->profile;
return $profiles;
{"id":1,"user_id":19,"hobby":"\u559c\u6b22\u5927\u59d0\u59d0","status":1}
//反向关联
//一对一也支持反向关联:定向反向关联;具体通过在 Profile 设置即可;
//profile.php //参数1为主表类 //参数2,3和正向一致,默认对应可以不写
//App\Http\Models文件下
namespace App\Http\Models;
use Illuminate\Database\Eloquent\Model;
class Profile extends Model
{
public function user(){
return $this->belongsTo(User::class,'user_id','id');
}
}
//控制器文件下
$user = Profile::find(1)->user;
return $user;
//{"id":19,"username":"\u8721\u7b14\u5c0f\u65b0","password":"123","gender":"\u7537","email":"[email protected]","price":"60.00","details":"123","uid":1001,"status":-1,"list":"{\"id\": 19, \"uid\": 1010}","deleted_at":null,"created_at":"2016-06-27T16:45:26.000000Z","updated_at":"2016-06-27T16:45:26.000000Z"}
//User.php对bool.php关联
public function book(){
return $this->hasMany(Book::class,'user_id','id');
}
//一对多
//得到蜡笔小新所有关联的书籍列表
$books = User::find(19)->book;
return $books;
[{"id":1,"user_id":19,"title":"\u300a\u838e\u58eb\u6bd4\u4e9a\u300b"},{"id":10,"user_id":19,"title":"\u300a\u70ed\u60c5\u5929\u5802\u300b"},{"id":11,"user_id":19,"title":"\u300a\u5b8c\u7f8e\u4eba\u751f\u300b"},{"id":29,"user_id":19,"title":"\u300a\u54c8\u5229\u6ce2\u7279\u300b"}]
//多对一
//book.php 关联 user.php model
public function user(){
return $this->belongsTo(User::class,'user_id','id');
}
//控制器
$users = Book::find(11)->user;
return $users;
{"id":19,"username":"\u8721\u7b14\u5c0f\u65b0","password":"123","gender":"\u7537","email":"[email protected]","price":"60.00","details":"123","uid":1001,"status":-1,"list":"{\"id\": 19, \"uid\": 1010}","deleted_at":null,"created_at":"2016-06-27T16:45:26.000000Z","updated_at":"2016-06-27T16:45:26.000000Z"}
//正向
//user.php 关联 中间role_user 在关联 role
public function role(){
return $this->belongsToMany(
Role::class,
'role_user',
'user_id',
'role_id',
'id'
);
}
//关联关系
// 表user(主键id->user_id)->表role_user(role_id )->表role(id->role_id)
$users = User::find(19)->role;
return $users;
[{"id":2,"type":"\u8bc4\u8bba\u5ba1\u6838\u4e13\u5458","pivot":{"user_id":19,"role_id":2}},{"id":3,"type":"\u56fe\u7247\u76d1\u5bdf\u5458","pivot":{"user_id":19,"role_id":3}},{"id":1,"type":"\u8d85\u7ea7\u7ba1\u7406\u5458","pivot":{"user_id":19,"role_id":1}}]
//获取权限列表中某一个数据,和一对多操作方法一样,但注意返回的表名称
//注意,多对多这里role()返回的是role_user 表 //可以通过dd($roles)查看,所以,where 需要用role_id 来指明 #table: "role_user"
$roles = User::find(19)->role()->where('role_id', 1)->get();
$users = User::find(19)->role;
Illuminate\Database\Eloquent\Relations\BelongsToMany {#1070 ▼
#table: "role_user"
#foreignPivotKey: "user_id"
#relatedPivotKey: "role_id"
#parentKey: "id"
#relatedKey: "id"
#relationName: "role"
#pivotColumns: []
#pivotWheres: []
#pivotWhereIns: []
#pivotWhereNulls: []
#pivotValues: []
+withTimestamps: false
#pivotCreatedAt: null
#pivotUpdatedAt: null
#using: null
#accessor: "pivot"
#query: Illuminate\Database\Eloquent\Builder {#281 ▶}
#parent: App\Http\Models\User {#1069 ▶}
#related: App\Http\Models\Role {#276 ▶}
//也可以用集合的方法来处理
$users = User::find(19)->role;
//dd($users);
[{"id":2,"type":"\u8bc4\u8bba\u5ba1\u6838\u4e13\u5458","pivot":{"user_id":19,"role_id":2}},{"id":3,"type":"\u56fe\u7247\u76d1\u5bdf\u5458","pivot":{"user_id":19,"role_id":3}},{"id":1,"type":"\u8d85\u7ea7\u7ba1\u7406\u5458","pivot":{"user_id":19,"role_id":1}}]
$user = $users->where('id',1);
return $user;
{"2":{"id":1,"type":"\u8d85\u7ea7\u7ba1\u7406\u5458","pivot":{"user_id":19,"role_id":1}}}
//反向 多对多
// Role(主键id->role_id)->表role_user(role_id )->表role(id->user_id)
namespace App\Http\Models;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
public function user(){
return $this->belongsToMany(
User::class,
'role_user',
'role_id',
'user_id'
);
}
}
$users = Role::find(1)->user;
return $users;
[{"id":24,"username":"\u5c0f\u660e","password":"123","gender":"\u7537","email":"[email protected]","price":"90.00","details":"123","uid":1004,"status":2,"list":null,"deleted_at":null,"created_at":"2016-08-27T23:50:52.000000Z","updated_at":"1997-01-01T01:01:01.000000Z","pivot":{"role_id":1,"user_id":24}},{"id":19,"username":"\u8721\u7b14\u5c0f\u65b0","password":"123","gender":"\u7537","email":"[email protected]","price":"60.00","details":"123","uid":1001,"status":-1,"list":"{\"id\": 19, \"uid\": 1010}","deleted_at":null,"created_at":"2016-06-27T16:45:26.000000Z","updated_at":"2016-06-27T16:45:26.000000Z","pivot":{"role_id":1,"user_id":19}},{"id":99,"username":"\u795e\u56fd","password":"123","gender":"\u7537","email":"[email protected]","price":"0.00","details":"123","uid":null,"status":0,"list":null,"deleted_at":null,"created_at":"2020-05-04T04:52:06.000000Z","updated_at":"2020-06-30T01:49:01.000000Z","pivot":{"role_id":1,"user_id":99}}]
//集合的方法取
$users = Role::find(1)->user;
$user = $users->where('id',19);
return $user;
{"1":{"id":19,"username":"\u8721\u7b14\u5c0f\u65b0","password":"123","gender":"\u7537","email":"[email protected]","price":"60.00","details":"123","uid":1001,"status":-1,"list":"{\"id\": 19, \"uid\": 1010}","deleted_at":null,"created_at":"2016-06-27T16:45:26.000000Z","updated_at":"2016-06-27T16:45:26.000000Z","pivot":{"role_id":1,"user_id":19}}}
//user.php model
//多对多会生成一个中间字段:urr,里面包含多对多的双 id;
//想要 urr 字段包含更多的中间表字段,可以自行添加,还可以修改字段名
public function role(){
return $this->belongsToMany(
Role::class,
'role_user',
'user_id',
'role_id',
'id')
->withPivot('details','id')
->as('urr');
}
$users = User::find(19)->role;
return $users;
[{"id":2,"type":"\u8bc4\u8bba\u5ba1\u6838\u4e13\u5458","urr":{"user_id":19,"role_id":2,"details":"\u55ef","id":1}},{"id":3,"type":"\u56fe\u7247\u76d1\u5bdf\u5458","urr":{"user_id":19,"role_id":3,"details":"\u556a","id":6}},{"id":1,"type":"\u8d85\u7ea7\u7ba1\u7406\u5458","urr":{"user_id":19,"role_id":1,"details":"\u5566","id":8}}]
public function role(){
return $this->belongsToMany(
Role::class,
'role_user',
'user_id',
'role_id',
'id')
->withPivot('details','id')
->wherePivot('id',1)
->as('urr');
}
$users = User::find(19)->role;
return $users;
[{"id":2,"type":"\u8bc4\u8bba\u5ba1\u6838\u4e13\u5458","urr":{"user_id":19,"role_id":2,"details":"\u55ef","id":1}}]
$books = User::find(19)->book;
//$_books = User::find(19)->book()->toSql();
//"select * from `laravel_books` where `laravel_books`.`user_id` = ? and `laravel_books`.`user_id` is not null"
$_books = User::find(19)->book()->get();
//这两个查询相等
//可以采用where 筛选或闭包
$books = User::find(19)->book() ->where('id', 1)->orWhere('id', 11)->get();
//select * from `laravel_books` where `laravel_books`.`user_id` = ? and `laravel_books`.`user_id` is not null and `id` = ? or `id` = ?
$books = User::find(10)->book()->where(function ($query) { $query->where('id', 1)->orWhere('id', 11); })->get();
[{"id":1,"user_id":19,"title":"\u300a\u838e\u58eb\u6bd4\u4e9a\u300b"},{"id":11,"user_id":19,"title":"\u300a\u5b8c\u7f8e\u4eba\u751f\u300b"}]
//select * from `laravel_books` where `laravel_books`.`user_id` = ? and `laravel_books`.`user_id` is not null and (`id` = ? or `id` = ?)
//使用 has()方法,可以查询某些条件下的关联查询数据
//获取存在关联书籍的用户列表(言下之意:至少一本书)
//select * from `laravel_users` where exists (select * from `laravel_books` where `laravel_users`.`id` = `laravel_books`.`user_id`)
$users = User::has('book')->get();
return $users;
//获取存在关联书籍(并超过3条)的用户列表
$users = User::has('book','>=',3)->toSql();
//select * from `laravel_users` where (select count(*) from `laravel_books` where `laravel_users`.`id` = `laravel_books`.`user_id`) >= 3
//使用 whereHas()方法,创建闭包查询
$users = User::whereHas('book', function ($query) {
//这里$query是book 表,通过user_id 查询,返回user 表数据
$query->where('user_id', 19);
})->get();
//使用 whereHas()方法,创建闭包查询;
//whereHas闭包用法
$users = User::whereHas('book', function ($query) {
//这里$query是book 表,通过user_id 查询,返回user 表数据
$query->where('user_id', 19);
})->get();
//elect * from `laravel_users` where exists (select * from `laravel_books` where `laravel_users`.`id` = `laravel_books`.`user_id` and `user_id` = ?)
return $users;
[{"id":19,"username":"\u8721\u7b14\u5c0f\u65b0","password":"123","gender":"\u7537","email":"[email protected]","price":"60.00","details":"123","uid":1001,"status":-1,"list":"{\"id\": 19, \"uid\": 1010}","deleted_at":null,"created_at":"2016-06-27T16:45:26.000000Z","updated_at":"2016-06-27T16:45:26.000000Z"}]
//使用 doesntHave()方法,即 has()的反向操作;
//获取不存在关联书籍的用户列表,闭包用法: whereDoesntHave()
$users = User::doesntHave('book')->toSql();
//
select * from `laravel_users` where not exists (select * from `laravel_books` where `laravel_users`.`id` = `laravel_books`.`user_id`)
return $users;
//使用 withCount()方法,可以进行关联统计;
//关联统计,会自动给一个book_count 字段 //统计每个用户有多少本书
$users = User::withCount('book')->toSql(); return $users;
//select `laravel_users`.*, (select count(*) from `laravel_books` where `laravel_users`.`id` = `laravel_books`.`user_id`) as `book_count` from `laravel_users`
//给多个关系添加统计:profile_count,book_count
$users = User::withCount(['profile', 'book'])->get(); return $users;
//select `laravel_users`.*, (select count(*) from `laravel_profiles` where `laravel_users`.`id` = `laravel_profiles`.`user_id`) as `profile_count`, (select count(*) from `laravel_books` where `laravel_users`.`id` = `laravel_books`.`user_id`) as `book_count` from `laravel_users`
$users = User::withCount(['profile', 'book' => function ($query) {
//这里限制被统计的记录
$query->where('user_id', 19);
}])
->get();
return $users;
//select `laravel_users`.*, (select count(*) from `laravel_profiles` where `laravel_users`.`id` = `laravel_profiles`.`user_id`) as `profile_count`, (select count(*) from `laravel_books` where `laravel_users`.`id` = `laravel_books`.`user_id` and `user_id` = ?) as `book_count` from `laravel_users`
[{"id":19,"username":"\u8721\u7b14\u5c0f\u65b0","password":"123","gender":"\u7537","email":"[email protected]","price":"60.00","details":"123","uid":1001,"status":-1,"list":"{\"id\": 19, \"uid\": 1010}","deleted_at":null,"created_at":"2016-06-27T16:45:26.000000Z","updated_at":"2016-06-27T16:45:26.000000Z","profile_count":1,"book_count":4},
{"id":20,"username":"\u8def\u98de","password":"123","gender":"\u7537","email":"[email protected]","price":"70.00","details":"123","uid":1002,"status":0,"list":null,"deleted_at":null,"created_at":"2016-06-27T16:55:56.000000Z","updated_at":"1997-01-01T01:01:01.000000Z","profile_count":1,"book_count":0},{"id":21,"username":"\u9ed1\u5d0e\u4e00\u62a4","password":"456","gender":"\u7537","email":"[email protected]","price":"80.00","details":"123","uid":1003,"status":1,"list":null,"deleted_at":null,"created_at":"2016-07-27T17:22:16.000000Z","updated_at":"1997-01-01T01:01:01.000000Z","profile_count":1,"book_count":0},
.....
//获取所有书籍列表
$books = Book::all();
//遍历每一本书
foreach ($books as $book) {
//每一本书的关联用户的姓名
DebugBar::info($book->user->username);
}
PS:通过调试器 Debugbar 中 SQL 语句的分析,发现包含十多条 SQL 语句;
PS:原因是关联查询时,每遍历一次就会执行一遍 SQL 语句,导致性能欠佳;
PS:所谓 N+1 条,就是起初获取全部数据的 1 条和,遍历的 N 条
使用 with()关键字,进行预载入设置,提前将 SQL 整合;
//with关键字预载入
$books = Book::with('user')->get();
foreach ($books as $book) {
DebugBar::info($book->user->username);
}
PS:此时的 SQL 执行数目为:1+1 条;也支持数组多个关联 with[‘book’,‘prifile’];
PS:预加载也可以设置显示的列
//预载入设置指定的列
$books = Book::with('user:id,username')->get();
foreach ($books as $book) {
DebugBar::info($book->user->username);
}
//可以看出sql执行的条目会大大的减少
如果是每次都必须进行关联查询,可以在模型中定义
//book.php model
protected $with = ['user'];
这样就不需要使用with()方法了
#演示 取消模型$with,看预下载结合筛选;
$books = Book::with(['user' => function ($query) {
$query->where('id', 19);
}])->get();
PS:预载入筛选不可以使用 limit、take 方法;
有时可能产生逻辑判断是否查询数据,但预加载会提前关联执行;
这样会导致资源性能的浪费,此时可以采用延迟预载入;
$books = Book::all();
//if逻辑判断
if (true) {
$books = $books->load('user');
//load(['user' => function () {}])
foreach ($books as $book) {
DebugBar::info($book->user->username);
}
}
同理loadCount()方法,可以实现关联统计;
$users = User::all();
if (true) {
return $users->loadCount('book');
}