Laravel学习笔记基础系列--(二十六)Laravel 模型之间的关联关系

作者: 温新

分类: 【Laravel】

阅读: 1759

时间: 2021-07-27 15:10:47

作者:温新

时间: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');
}

关于基础的 一对一、一对多、多对多关联关系就记录到这里了。关联关系中最复杂最难以理解的就是多对多的关联关系,因此,需要多多练习。

对于参数的省略问题,建议把参数写全,便于理解与记忆。当对关联关系了然于胸时再省略也不迟。好了,基础的关联关系就记录到这里了。我是温新,欢迎和大家一起交流学习。

我是温新

每天进步一点点,就一点点

请登录后再评论