Laravel学习笔记基础系列--(二十六)Laravel 模型之间的关联关系
作者:温新
时间:2021-07-01
一个作者可以有多篇文章,一般情况下用的最多的是关联查询。当用了关联关系会,你会爱上她。少量代码就实现了关联之间的数据查询。
准备工作
我们已经有了users
表与posts
,这是一个一对多的关系,因此我们建立一个用户档案表,与users
表是一对一关系。
<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(170, 85, 0)">// 1、创建模型并生成迁移文件</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(0, 0, 0)">php</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">artisan</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">make</span>:<span style="box-sizing: border-box;color: rgb(0, 0, 0)">model</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">UserProfile</span> <span style="box-sizing: border-box;color: rgb(152, 26, 26)">-</span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">m</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(170, 85, 0)">// 2、迁移文件</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(0, 0, 0)">Schema</span>::<span style="box-sizing: border-box;color: rgb(0, 0, 0)">create</span>(<span style="box-sizing: border-box;color: rgb(170, 17, 17)">'user_profiles'</span>, <span style="box-sizing: border-box;color: rgb(119, 0, 136)">function</span> (<span style="box-sizing: border-box;color: rgb(0, 0, 0)">Blueprint</span> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$table</span>) {</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$table</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">id</span>();</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$table</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">integer</span>(<span style="box-sizing: border-box;color: rgb(170, 17, 17)">'user_id'</span>)<span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">unsigned</span>()<span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(119, 0, 136)">default</span>(<span style="box-sizing: border-box;color: rgb(17, 102, 68)">1</span>)<span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">unique</span>();</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$table</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">string</span>(<span style="box-sizing: border-box;color: rgb(170, 17, 17)">'id_card'</span>)<span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">nullable</span>()<span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">comment</span>(<span style="box-sizing: border-box;color: rgb(170, 17, 17)">'身份证'</span>);</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$table</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">timestamps</span>();</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">});</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(170, 85, 0)">// 3、php artisan migrate --path=database/migrations/2021_06_30_172431_create_user_profiles_table.php</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(170, 85, 0)">// 4、填充数据,自行执行</span></span>
一对一关联查询
hasOne正向关联
方法:hasOne($className,$foreignKey=null,$localKey=null
案例:hasOne('App\Models\UserProfile','user_id','id')
。
参数解释:
<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">return</span> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$this</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">hasOne</span>(<span style="box-sizing: border-box;color: rgb(0, 85, 170)">$className</span>,<span style="box-sizing: border-box;color: rgb(0, 85, 170)">$foreignKey</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">=</span><span style="box-sizing: border-box;color: rgb(34, 17, 153)">null</span>,<span style="box-sizing: border-box;color: rgb(0, 85, 170)">$localKey</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">=</span><span style="box-sizing: border-box;color: rgb(34, 17, 153)">null</span>);</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(0, 0, 0)">参数一:要关联的模型类名。</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">这里指</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">UserProfile模型</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(0, 0, 0)">参数二:要关联模型所属表中的外键。</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">这里指</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">user_profiles表中的user_id</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(0, 0, 0)">参数三:关联表的外键。</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">这里指</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">users表中的id</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(0, 0, 0)">hasOne要关联模型名所对应表的外键与关联表的主键关键</span></span>
案例:通过用户获取其档案信息
第一步:定义模型关联
位置:app/Models/User.php
<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(170, 85, 0)">// 推荐把参数写全</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">public</span> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">function</span> <span style="box-sizing: border-box;color: rgb(0, 0, 255)">userProfile</span>()</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">{</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">return</span> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$this</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">hasOne</span>(<span style="box-sizing: border-box;color: rgb(0, 0, 0)">UserProfile</span>::<span style="box-sizing: border-box;color: rgb(119, 0, 136)">class</span>, <span style="box-sizing: border-box;color: rgb(170, 17, 17)">'user_id'</span>, <span style="box-sizing: border-box;color: rgb(170, 17, 17)">'id'</span>);</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">}</span>
第二步:控制器使用
文件:DemoController.php
<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">public</span> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">function</span> <span style="box-sizing: border-box;color: rgb(0, 0, 255)">demo</span>()</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">{</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(170, 85, 0)">// 先获取用户信息,然再获取档案信息</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$user</span> <span style="box-sizing: border-box;color: rgb(152, 26, 26)">=</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">\App\Models\User</span>::<span style="box-sizing: border-box;color: rgb(0, 0, 0)">find</span>(<span style="box-sizing: border-box;color: rgb(17, 102, 68)">1</span>)<span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">userProfile</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">return</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">view</span>(<span style="box-sizing: border-box;color: rgb(170, 17, 17)">'demo.demo'</span>);</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">}</span>
控制器中调用时,是User
模型中的userProfile
方法当作一个动态属性来调用。
belongsTo反向关联
方法:belongsTo($className, $foreignKey = null, $ownerKey = null, $relation = null)
参数一:关联模型文件。如 User
;
参数二:当前模型外键,如UserProfile
模型的外键user_id
;
参数三:关键模型住建,如User
模型的id
;
第一步:定义模型方法
文件:app/Models/UserProfile.php
<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">public</span> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">function</span> <span style="box-sizing: border-box;color: rgb(0, 0, 255)">user</span>()</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">{</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">return</span> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$this</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">belongsTo</span>(<span style="box-sizing: border-box;color: rgb(0, 0, 0)">User</span>::<span style="box-sizing: border-box;color: rgb(119, 0, 136)">class</span>,<span style="box-sizing: border-box;color: rgb(170, 17, 17)">'user_id'</span>,<span style="box-sizing: border-box;color: rgb(170, 17, 17)">'id'</span>);</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">}</span>
第二步:控制器调用
文件:DemoController.php
<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">use</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">App\Models\UserProfile</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">public</span> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">function</span> <span style="box-sizing: border-box;color: rgb(0, 0, 255)">demo</span>()</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">{</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$userProfile</span> <span style="box-sizing: border-box;color: rgb(152, 26, 26)">=</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">UserProfile</span>::<span style="box-sizing: border-box;color: rgb(0, 0, 0)">find</span>(<span style="box-sizing: border-box;color: rgb(17, 102, 68)">1</span>)<span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">user</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">return</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">view</span>(<span style="box-sizing: border-box;color: rgb(170, 17, 17)">'demo.demo'</span>);</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">}</span>
一对多关联
一对多,如一个作者可以发布很多文章,再如一篇文章有N多评论,这都形成了一个一对多的关系。
hasMany正向关联
方法:hasMany($related, $foreignKey = null, $localKey = null)
参数一:关联模型,如关键Post模型;
参数二:关键外键ID,如 Post模型中的user_id;
参数三:本模型主键,如User模型的id
第一步:定义模型方法
文件:app/Models/User.php
<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">public</span> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">function</span> <span style="box-sizing: border-box;color: rgb(0, 0, 255)">posts</span>()</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">{</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">return</span> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$this</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">hasMany</span>(<span style="box-sizing: border-box;color: rgb(0, 0, 0)">Post</span>::<span style="box-sizing: border-box;color: rgb(119, 0, 136)">class</span>,<span style="box-sizing: border-box;color: rgb(170, 17, 17)">'user_id'</span>,<span style="box-sizing: border-box;color: rgb(170, 17, 17)">'id'</span>);</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">}</span>
第二步:控制器调用
文件:DemoController.php
$userPosts = User::find(1)->posts;
belongsTo反向关联
一个作者可以有多篇文章,那么返过来就是多篇文章属于某一个作者,也就是可以通过文章来反查作者信息。
方法:belongsTo($related, $foreignKey = null, $ownerKey = null, $relation = null)
参数一:关联模型,如User模型;
参数二:关键模型外键,如Post表中的user_id;
参数三:主键ID
第一步:定义模型方法
文件:app/Models/Post.php
public function userInfo()
{
return $this->belongsTo(User::class,'user_id','id');
}
第二步:控制器调用
文件:DemoController.php
public function demo()
{
$posts = Post::with('userInfo')->where('user_id',1)->get();
return view('demo.demo', compact('posts'));
}
获取文章信息时,可以通过with
方法并传入动态关联属性名(也就是方法)就可以一次完成动态关联查询。
这里可以dd($posts)
来看看,除了所有文章被查了出来之外,每个模型对象里面包有一个relations
属性,其中就有关联作者信息的userInfo
数组,这里面就包含了作者信息。
第三步:视图使用
文件:demo.blade.php
@foreach($posts as $post)
{{--文章标题--}}
{{$post->title}}
{{-- 作者名称--}}
{{$post->userInfo->name}}
@endforeach
多对多关联
一篇文件可以有多个标签,一个标签可能有属于多篇文章,那么,文章和标签之间就属于多对对的关系。要实现多对对关系就必须借助中间表来实现,为此我们需要创建一个中间表与标签表。
准备工作
创建Tag标签表
第一步:创建标签模型与迁移文件
php artisan make:model Tag -m
第二步:编写迁移文件
Schema::create('tags', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 100)->unique()->comment('标签名');
$table->timestamps();
});
第三步:创建中间表post_tags迁移文件
php artisan make:migration create_post_tags_table --create=post_tags
第四步:编写迁移文件
Schema::create('post_tags', function (Blueprint $table) {
$table->increments('id');
$table->integer('post_id')->unsigned()->default(1);
$table->integer('tag_id')->unsigned()->default(1);
$table->unique(['post_id', 'tag_id']);
$table->timestamps();
});
第五步:执行迁移
php artisan migrate --path=database/migrations/2021_07_01_150103_create_tags_table.php
php artisan migrate --path=database/migrations/2021_07_01_150504_create_post_tags_table.php
第六步:关于数据,请自行填充
belongsToMany正向关联
方法:belongsToMany($related, $table = null, $foreignPivotKey = null, $relatedPivotKey = null,$parentKey = null, $relatedKey = null, $relation = null)
暂时只用到前四个参数,因此只说前四个参数。
参数一:关联模型。这里是Tag模型;
参数二:中间表名,这里是post_tag中间表;
参数三:中间表关联外键ID,post_tag中间表的post_id;
参数四:中间表关联外键ID,post_tag中间表的tag_id;
参数五:当前模型的字段,默认Post模型的主键id;
参数六:关联模型的哪个字段,默认Tag模型的主键ID;
参数七:关联关系名称,默认是关联关系方法名
案例:获取一篇文章的所有标签
第一步:定义模型方法
文件:`app/Models/Post.php
public function tags()
{
return $this->belongsToMany(Tag::class,'post_tags','post_id','tag_id','id','id');
}
第二步:控制器调用
文件:DemoController.php
中的demo
方法
$post = Post::with('tags')->find(1);
belongsToMany反向关联
由于多对多关联关系之间是平等的,因此建立相对关联关系的方法是一样的。
案例:查找标签下的所有文章
第一步:定义模型关联
文件:app/Models/Tag.php
public function posts()
{
return $this->belongsToMany(Post::class,'post_tags','post_id','tag_id','id','id');
}
第二步:控制器调用
文件:DemoController.php
中的demo
方法
public function demo()
{
$tags = Tag::with('posts')->where('name','Laravel')->first();
dd($tags);
return view('demo.demo');
}
关于基础的 一对一、一对多、多对多关联关系就记录到这里了。关联关系中最复杂最难以理解的就是多对多的关联关系,因此,需要多多练习。
对于参数的省略问题,建议把参数写全,便于理解与记忆。当对关联关系了然于胸时再省略也不迟。好了,基础的关联关系就记录到这里了。我是温新,欢迎和大家一起交流学习。
我是温新
每天进步一点点,就一点点