参考文章
 
以下所用到的实例,包含在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. pure响应式布局

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  2. C#基础知识图谱

  3. mac 查看python安装路径

    1.terminal : input: which Python 2.terminal: input : python  --->import sys  ----> print sys.p ...

  4. win10蓝牙添加设备无法连接

    解决方法: 打开运行窗口,输入services.msc. 找到蓝牙支持服务(或者Bluetooth Support Service),右键,属性,启动类型选择手动,启动服务. 还不行的话,此电脑右键, ...

  5. Hybris ECP里Customer对应的数据库表

    SAP CRM里Account明细页面: SAP C4C里Account明细页面: 在Hybris storefront注册一个帐号: 注册成功之后能在backoffice里看到成功生成的custom ...

  6. IOS 响应者链条 and UIGestureRecognizer 手势识别器)

    一次完整的触摸事件的传递响应的过程 UIAppliction --> UIWiondw -->递归找到最适合处理事件的控件 控件调用touches方法-->判断是否实现touches ...

  7. 如何修改集群的公网信息(包括 VIP) (文档 ID 1674442.1)

    适用于: Oracle Database - Enterprise Edition - 版本 11.2.0.3 到 12.1.0.2 [发行版 11.2 到 12.1]本文档所含信息适用于所有平台 用 ...

  8. netbackup :nbu备份 Hyper-V 遇到快照错误(状态码 156)

    遇到快照错误(状态码 156) 下表介绍与 NetBackup 状态码 156 有关的 Hyper-V 问题. 表:状态码 156 的可能原因 状态码 156 的原因 说明及推荐操作 NetBacku ...

  9. CUDA实现数组倒序

    数组倒序,将在主机上初始化的数组传输到设备上,然后用CUDA并行倒序,此时在全局内存上操作,再将结果返回到主机并验证. #include <stdio.h> #include <as ...

  10. C#Json数据交互

    问题:写项目时,难免会遇到前台和后台要进行数据交换,往前台传一个对象或一个对象集,往后台传一个对象,一个对象集.怎么传,你当然不能直接去传递一个对象或对象集,我们可以利用JSON数据相互之间传值. J ...