• laravel5.2总结--关联关系


     参考文章
     
    以下所用到的实例,包含在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('AppModelsUserAccounts'); }
    注意:hasOne()方法的3种不同的使用情况: Eloquent 默认关联关系的外键基于模型名称。默认是:UserAccount模型的主键是id,关联的外键是user_id  
    1> hasOne('AppModelsUserAccounts') - 默认情况  
    2> hasOne('AppModelsUserAccounts', 'foreign_key') -UserAccount模型的主键是id,但是外键不是 user_id  
    3> hasOne('AppModelsUserAccounts', '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('AppModelsUser'); }
    注意:belongsTo()方法的3种不同的使用情况: Eloquent 默认关联关系的外键基于关联方法名称。默认是:UserAccount模型的主键是id,关联的外键是user_id  
    1> belongsTo('AppModelsUser') - 默认情况  
    2> belongsTo('AppModelsUser', 'foreign_key') -UserAccount模型的主键是id,但是外键不是 user_id  
    3> belongsTo('AppModelsUser', '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('AppModelsPost'); }
    当然,因为所有的关联也都提供了查询语句构造器的功能,因此你可以对获取到的评论进一步增加条件,通过调用 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('AppModelsUser'); }
    //2> 当定义的方法名不是user的时候,传入了额外参数,意为posts表中的user_id对应users表中的id
    public function author() { return $this->belongsTo('AppModelsUser', '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('AppModelsRole'); }
    注意:
    完整写法:
    return $this->belongsToMany('AppModelsRole', 'user_roles', 'user_id', 'role_id');
    Eloquent 会合并两个关联模型的名称并依照字母顺序命名。当然你也可以随意重写这个约定。可通过传递第二个参数至 belongsToMany 方法来实现:
    return $this->belongsToMany('AppModelsRole', 'user_roles');
    除了自定义合并数据表的名称,你也可以通过传递额外参数至 belongsToMany 方法来自定义数据表里的键的字段名称。第三个参数是你定义在关联中的模型外键名称,而第四个参数则是你要合并的模型外键名称:
     
    3.3 相对的我们也可以在模型Role中定义获取对应User模型的方法:
    public function getUsers() { return $this->belongsToMany('AppModelsUsers'); }
     
    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('AppRole')->withPivot('column1', 'column2');
    如果你想要中间表自动维护 created_at 和 updated_at 时间戳,可在定义关联方法时加上 withTimestamps 方法:
    return $this->belongsToMany('AppRole')->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('AppModelsPost','AppModelsUser'); }
    其中第一个参数是关联对象类名,第二个参数是中间对象类名。
    当运行关联查找时,通常会使用 Eloquent 的外键约定。如果你想要自定义关联的键,则可以将它们传递至 hasManyThrough 方法的第三与第四个参数。第三个参数为中间模型的外键名称,而第四个参数为最终模型的外键名称.
    $this->hasManyThrough('AppModelsPost','AppModelsUser',$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('AppModelsComment','item'); }
     
    同样也可以在Comment模型中定义相对的关联关系获取其所属节点:
    public function item() { return $this->morphTo(); }
    //扩展,当不使用item作为方法名,可以传入自定义参数
    public function getItem()
    {
    return $this->morphTo('item', 'item_type', 'item_id');
    }
     
    完整写法:
    1> $this->morphMany('AppModelsComment',$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('AppModelsTag','taggable'); }
    在Tag中定义相对的关联关系如下:
    public function posts() { return $this->morphedByMany('AppModelsPost','taggable'); } public function videos() { return $this->morphedByMany('AppModelsVideo','taggable'); }
    完整写法:
    1> $this->morphToMany('AppModelsTag','taggable','taggable','taggable_id','tag_id',false);
    其中第一个参数是关联模型类名,第二个参数是关联关系名称,其中第三个参数是对应关系表名,最后一个值若为true,则查询的是关联对象本身,若为false,查询的是关联对象与父模型的对应关系。
    2> $this->morphedByMany('AppModelsVideo','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);
    }
    结果:
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    linux
    JAVA——遍历
    linux基础命令
    Java的反射和代理以及注解
    web 前端遇到的问题
    JTopo 使用
    阿里云服务器linux(cenos)下 jdk、tomcat的安装配置
    笔记--数据库总结
    0.01的区别
    犹豫——辛苦——坚持——收获 (2019北航软工培训总结)
  • 原文地址:https://www.cnblogs.com/redirect/p/6215334.html
Copyright © 2020-2023  润新知