参考文章
 
以下所用到的实例,包含在https://github.com/archer-wong/laravel-orm-relationships工程中,方便使用。
 
你可在 Eloquent 模型类内将 Eloquent 关联定义为函数。因为关联像 Eloquent 模型一样也可以作为强大的查询语句构造器,定义关联为函数提供了强而有力的链式调用及查找功能。
 

1 一对一关系

1.1 表A和表B的记录一一对应,比如一个用户对应一个社交账号
 
1.2 定义模型User(位于app/Models文件夹下),并在其中定义与UserAccount的一对一对应关系:
public function getAccount() { return $this->hasOne('App\Models\UserAccounts'); }
注意:hasOne()方法的3种不同的使用情况: Eloquent 默认关联关系的外键基于模型名称。默认是:UserAccount模型的主键是id,关联的外键是user_id  
1> hasOne('App\Models\UserAccounts') - 默认情况  
2> hasOne('App\Models\UserAccounts', 'foreign_key') -UserAccount模型的主键是id,但是外键不是 user_id  
3> hasOne('App\Models\UserAccounts', 'foreign_key', 'local_key') - UserAccount模型的主键不是id,外键也不是user_id  
第一个参数是关联模型的类名称,
第二个参数,Eloquent 会假设对应关联的外键名称是基于模型名称的,会取用自身模型的「蛇形命名」后的名称,并在后方加上 _id,所以定义模型时候要注意,模型的名称加上'_id'的组合作为外键,我们这里外键=>'user'+'_id',也就是$foreign_key = 'user_id'
第三个参数,Eloquent 的默认外键在上层模型的 id 字段会有个对应值。
 
1.3 我们也可以在UserAccount模型中定义与User的一对一关系:
public function user() { return $this->belongsTo('App\Models\User'); }
注意:belongsTo()方法的3种不同的使用情况: Eloquent 默认关联关系的外键基于关联方法名称。默认是:UserAccount模型的主键是id,关联的外键是user_id  
1> belongsTo('App\Models\User') - 默认情况  
2> belongsTo('App\Models\User', 'foreign_key') -UserAccount模型的主键是id,但是外键不是 user_id  
3> belongsTo('App\Models\User', 'foreign_key', 'local_key') - UserAccount模型的主键不是id,外键也不是user_id  
默认情况下,Eloquent将调用belongsTo的关联方法名user作为关联关系$relation的值,并将$relation.'_id'作为默认外键名对应users表的id,如果表中没有相应列,又没有在定义关联关系的时候指定具体的外键,就会报错。
 
1.4 控制器中的调用
public function oneToOne(){
$user_account = User::find(1)->getAccount;
$user = UserAccount::find(1)->user;
dd($user_account, $user);
}
调用:  
关联关系被定义后,可以使用 Eloquent 的 '动态属性' 来获取关联关系!  
注意:  
动态属性:允许我们访问关联函数,就像它们是定义在模型上的属性一样!         
理解 '动态属性' 的概念:按理说,我们定义了 getAccount() 方法,应该调用的是一个方法,而这里将其作为了一个 '属性' 来调用!  
 
1.5 总结:不管是User模型类,还是UserAccount模型类,2者都是以 'User' 模型为主。UserAccount模型还是附属于User模型。UserAccount模型具有外键 'user_id' ,但是要注意hasOne()方法的外键基于模型名称,belongsTo()方法的外键基于关联方法名称的。
调用结果:

2 一对多关系

2,1 表A的某条记录对应表B的多条记录,反之表B的某条记录归属于表A的某条记录,比如一个用户发表多篇文章
2.2 我们在用户模型User中定义与文章模型Post的一对多关系如下:
public function getPosts() { return $this->hasMany('App\Models\Post'); }
当然,因为所有的关联也都提供了查询语句构造器的功能,因此你可以对获取到的评论进一步增加条件,通过调用 posts()方法然后在该方法后面链式调用查询条件:
$posts = User::find(1)->getPosts()->where('title','vitae')->get(); dd($posts);
需要注意的是这里我们调用的是getPosts()方法,而不是动态属性getPosts,当然使用getPosts动态属性也可以支持链式调用。
 
2.3 同样,我们可以在文章模型Post中定义文章所属用户模型User的对应关系:
//1> 最基本写法
public function user() { return $this->belongsTo('App\Models\User'); }
//2> 当定义的方法名不是user的时候,传入了额外参数,意为posts表中的user_id对应users表中的id
public function author() { return $this->belongsTo('App\Models\User', 'user_id', 'id'); }
2.4 控制器中调用
public function oneToMany(){
$post = User::find(1)->getPosts;
//如果我们想增加更多的附加条件,可以使用posts()方法,这样仍然支持链式。
$post2 = User::find(1)->getPosts()->where('title','vitae')->get();
//区分user和user2的区别
$user = Post::find(1)->user;
$user2 = Post::find(1)->user();
//注意author方法的话,需要增加键的限制
$author = Post::find(1)->author;
dd($post, $post2, $user, $user2, $author);
}
2.4 总结
写法和一对一关系中非常相像。

3 多对多关系

3.1 表A的某条记录通过中间表C与表B的多条记录关联,反之亦然。比如一个用户有多种角色,反之一个角色对应多个用户。
 
提示:定义中间表的时候没有在结尾加s并且命名规则是按照字母表顺序,将role放在前面,user放在后面,并且用_分隔,在定义多对多关联的时候如果没有指定中间表,Eloquent默认的中间表使用这种规则拼接出来,比如模型1 user,模型2 role 那么表名就是role_user,Eloquent默认的中间表使用这种规则拼接出来。
 
3.2 我们在模型User中定义多对多关联如下:
public function getRoles() { return $this->belongsToMany('App\Models\Role'); }
注意:
完整写法:
return $this->belongsToMany('App\Models\Role', 'user_roles', 'user_id', 'role_id');
Eloquent 会合并两个关联模型的名称并依照字母顺序命名。当然你也可以随意重写这个约定。可通过传递第二个参数至 belongsToMany 方法来实现:
return $this->belongsToMany('App\Models\Role', 'user_roles');
除了自定义合并数据表的名称,你也可以通过传递额外参数至 belongsToMany 方法来自定义数据表里的键的字段名称。第三个参数是你定义在关联中的模型外键名称,而第四个参数则是你要合并的模型外键名称:
 
3.3 相对的我们也可以在模型Role中定义获取对应User模型的方法:
public function getUsers() { return $this->belongsToMany('App\Models\Users'); }
 
3.4 此外我们还可以通过动态属性pivot获取中间表字段:
$roles = Users::find(1)->roles; foreach ($roles as $role) { echo $role->pivot->role_id.'<br>'; }
注意:我们取出的每个 Role 模型对象,都会被自动赋予 pivot 属性。此属性代表中间表的模型,它可以像其它的 Eloquent 模型一样被使用。
默认情况下,pivot 对象只提供模型的键。
如果你的 pivot 数据表包含了其它的属性,则可以在定义关联方法时指定那些字段:
return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');
如果你想要中间表自动维护 created_at 和 updated_at 时间戳,可在定义关联方法时加上 withTimestamps 方法:
return $this->belongsToMany('App\Role')->withTimestamps();
 
3.5 控制器中调用:
public function manyToMany(){
$roles = User::find(1)->getRoles;
$users = Role::find(1)->getUsers;
//通过动态属性pivot获取中间表字段
foreach ($roles as $role) {
$pivot = $role->pivot->role_id;
echo $pivot . '<br>';
}
dd($roles, $users);
}
 

4 远层一对多

4.1 所谓的“远层一对多”指的是通过一个中间关联对象访问远层的关联关系,比如国家与用户之间存在一对多关系,用户与文章之间也存在一对多关系,那么通过用户可以建立国家与文章的之间的一对多关联关系,我们称之为“远层一对多”。
4.2 我们创建一个模型Country,并在其中定义国家与文章的远层一对多关系如下:
public function getPostsThroughUser() { return $this->hasManyThrough('App\Models\Post','App\Models\User'); }
其中第一个参数是关联对象类名,第二个参数是中间对象类名。
当运行关联查找时,通常会使用 Eloquent 的外键约定。如果你想要自定义关联的键,则可以将它们传递至 hasManyThrough 方法的第三与第四个参数。第三个参数为中间模型的外键名称,而第四个参数为最终模型的外键名称.
$this->hasManyThrough('App\Models\Post','App\Models\User',$country_id,$user_id);
4.3 接下来我们在控制器中定义测试代码如下:
public function hasManyThrough(){
$country = Country::find(1);
$posts = $country->getPostsThroughUser;
echo 'Country#'.$country->name.'下的文章:<br>';
foreach($posts as $post){
echo '&lt;&lt;'.$post->title.'&gt;&gt;<br>';
}
}
 
页面会输出:该国家下对应的所有文章
Country#China下的文章:
<<vitae>>
<<officiis>>
<<hic>>
<<quam>>
<<veritatis>>
 

5 多态关联

5.1 多态关联允许一个模型在单个关联下属于多个不同父模型。比方,某一条评论可能归属于某篇文章,也可能归属于某个视频。我们可以在评论表中添加一个item_id字段表示其归属节点ID,同时定义一个item_type字段表示其归属节点类型。
 
5.2 分别定义三个模型
在Post和Video模型类中定义关联评论:
public function comments() { return $this->morphMany('App\Models\Comment','item'); }
 
同样也可以在Comment模型中定义相对的关联关系获取其所属节点:
public function item() { return $this->morphTo(); }
//扩展,当不使用item作为方法名,可以传入自定义参数
public function getItem()
{
return $this->morphTo('item', 'item_type', 'item_id');
}
 
完整写法:
1> $this->morphMany('App\Models\Comment',$item,$item_type,$item_id,$id);
其中第一个参数是关联模型类名,第二个参数是关联名称,即$item_id和$item_type中的$item部分,最后一个参数是posts/videos表的主键。
2> $this->morphTo($item,$item_type,$item_id); 如果$item部分不等于item可以自定义传入参数到morphTo:
 
5.3 控制器中调用:
public function polymorphicRelations(){
$video = Video::find(1);
$videoComments = $video->comments;
$comment = Comment::find(1);
$item = $comment->item;
dd($videoComments, $item);
}
 
输出结果如下
 
 

6 多态多对多关联

6.1 最常见的应用场景就是标签,比如一篇文章对应多个标签,一个视频也对应多个标签,同时一个标签可能对应多篇文章或多个视频,
 
6.2 定义模型方法
在Post/Video中定义关联关系如下:
public function tags() { return $this->morphToMany('App\Models\Tag','taggable'); }
在Tag中定义相对的关联关系如下:
public function posts() { return $this->morphedByMany('App\Models\Post','taggable'); } public function videos() { return $this->morphedByMany('App\Models\Video','taggable'); }
完整写法:
1> $this->morphToMany('App\Models\Tag','taggable','taggable','taggable_id','tag_id',false);
其中第一个参数是关联模型类名,第二个参数是关联关系名称,其中第三个参数是对应关系表名,最后一个值若为true,则查询的是关联对象本身,若为false,查询的是关联对象与父模型的对应关系。
2> $this->morphedByMany('App\Models\Video','taggable','taggable','tag_id','taggable_id');
其中第一个参数是关联对象类名,第二个参数是关联关系名称,其中第三个参数是对应关系表名。
 
6.3 控制器中调用
public function manyToManyPolymorphicRelations(){
$post = Post::find(1);
$tags = $post->tags;
$tag = Tag::find(1);
$posts = $tag->posts;
dd($tags, $posts);
}
结果:
 
 
 
 
 
 
 
 
 

laravel5.2总结--关联关系的更多相关文章

  1. laravel5.3统计 withCount()方法的使用

    在laravel5.3之后可以使用withCount()这个方法. 注意:一定要是5.3版本之后,5.2和5.1都会报方法未定义 举个栗子: App\Post::withCount('comments ...

  2. 【laravel5.4 + TP5.0】hasOne和belongsTo的区别

    1.从字面理解:假如A比B大,那么A hasOne B: B belongsTo A: 2.个人总结: 3.从代码角度: 主要是看你是在哪一个model(模型)中编写这个关联关系,父关联对象就是在父关 ...

  3. laravel5.6 ORM 关联模型,一对一和一对多

    Laravel5.6 关联模型的操作,主要是一对一,一对多,多对多等操作.下面示例主要解析前面两个操作用法比较常用.(操作和用法TP5类似)将关联查询使用语法hasOne.hasMany.belong ...

  4. 【原】使用Bmob作为iOS后台开发心得——查询关联关系(BmobRelation)

    本文转载请注明出处 —— polobymulberry-博客园 简介 Bmob中的数据关联分为Pointer和Relation两种(数据关联在我开发app过程中使用还是很频繁的,也算个难点.虽然之前没 ...

  5. Hibernate(6)—— 一对多 和 多对多关联关系映射(xml和注解)总结

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的知识点总结如下: One to Many 映射关系 多对一单向外键关联(XML/Annotation) 一对多单向外键关联(XM ...

  6. Hibernate(5)—— 联合主键 、一对一关联关系映射(xml和注解) 和 领域驱动设计

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的知识点总结如下: One to One 映射关系 一对一单向外键(XML/Annotation) 一对一双向外键关联(XML/A ...

  7. laravel5 安装笔记

    1.环境更新 apt-get update apt-get install php5-cli apt-get install curl 2. Composer安装 curl -sS https://g ...

  8. Laravel5路由/home页面无法访问

    报错信息: Not Found The requested URL /laravel5/public/home was not found on this server. 解决方法: 1.编辑apac ...

  9. Laravel5.0学习--03 Artisan命令

    本文以laravel5.0.22为例. 简介 Artisan 是 Laravel 内置的命令行接口.它提供了一些有用的命令协助您开发,它是由强大的 Symfony Console 组件所驱动.利用它, ...

随机推荐

  1. Javascript Functions

    Javascript 全局对象 全局属性和函数可用于所有内建的Javascript对象 顶层函数(全局函数) decodeURI()解码某个编码的URI. decodeURIComponent()解码 ...

  2. socket网络套节字---聊天室

    一:服务端: 1.创建客户端: package com.ywh.serversocket; import java.io.InputStream; import java.io.OutputStrea ...

  3. Java开发工具IntelliJ IDEA本地历史记录的使用方法

    IntelliJ IDEA的本地历史记录可以帮助用户记录并跟踪本地项目的更改,防止项目的意外丢失或来源于IDE之外的项目更改.本教程将展示如何使用本地历史记录查看和恢复某些项目更改. 1 .从头开始创 ...

  4. JAXB介绍一

    参考博客: https://www.cnblogs.com/chenbenbuyi/p/8283657.html https://www.cnblogs.com/cnsdhzzl/p/8390514. ...

  5. PHP函数:mysql_fetch_assoc指针重置

    本文目前主要讨论mysql_fetch_assoc“指针”如何重置的问题 要了解mysql_fetch_assoc,先看看它与mysql_fetch_row和mysql_fetch_array的关系. ...

  6. LAMP Stack 5.7.16 (Ubuntu 16.04.1)

    平台: Ubuntu 类型: 虚拟机镜像 软件包: apache2.4 mysql5.7 php7 phpmyadmin4.5 apache application server basic soft ...

  7. cms-框架搭建

    1.web.xml中的配置,在配置中主要有: 1.1.过滤器: 1.1.1:shiro权限过滤器 1.1.2:字符编码过滤器 1.2.监听器: 1.2.1:spring监听器 1.3.servlet ...

  8. NetTime——c++实现计算机时间与网络时间的更新

    <Windows网络与通信程序设计>第二章的一个小例子,网络编程入门. #include "stdafx.h" #include <WinSock2.h> ...

  9. ABAP和Hybris的源代码生成工具

    ABAP 有两种方式,一种是ABAP Code Composer, 细节可以查看我的博客Step by Step to generate ABAP code automatically using C ...

  10. Select与SelectMany

    SelectMany在MSDN中的解释:将序列的每个元素投影到 IEnumerable(T) 并将结果序列合并为一个序列. 不用去用foreach进行两次遍历,就可以将子循环需要的元素过滤出来... ...