zoukankan      html  css  js  c++  java
  • laravel model relationship

    laravel支持多种模型之间的relation,对应着模型间的one2one, one2many,many2many,hasManyThrough,Polymorphic, many2many polymorphic关系。

    心法

    1.所有relation都由model class上的方法来定义;

    2. relationship和model本身都是以query builder作为基类的,因此对relation的操作也可以使用类似query builder的方法,比如:可以支持级联;

    3.Dynamic property of model:这是 model->relation方式引用的结果,这种方式直接返回relation model的value,不支持query builder的级联操作,这是和model->relation()方法调用的本质区别。

    也就是说model->relation = model->relation()->get()

    关系的种类:

    one 2 one(一对一)

    例子User hasOne Phone, Phone belongsTo User这种关系。要使得这种关系work,则需要以下前提:

    1. User模型

    base table: users,

    字段预设: id

    relation method: phone (){ return $this->hasOne('AppPhone') }

    注意:按照laravel的命名规约,laravel会假设phones表中有一个user_id字段作为users表中的id外键,

    我们可以通过在user()方法中传入另外的参数来覆盖这种规约,比如$this->hasOne('AppPhone','owner_id')

    在这里owner_id就是phones表中外键引用users表的id的字段名称(默认为user_id);

    2.Phone模型

    base table: phones,

    字段预设: user_id

    relation method: user(){ return $this->belongsTo('AppUser')}

    在这里,laravel也会预设parent表(也就是users表)中有一个id字段为primary key,如果你的parent表并不是使用id作为主键,则在上面的hasOne调用中,可以使用第三个参数来指定这个主键,比如

    user(){return $this->hasOne('AppUser','owner_id','u_id'}. 这里owner_id为phones表中对users表主键(u_id)的外键引用字段名称

    One 2 Many(一对多)

    例子: Post hasMany Comments, Comment belongsTo Post,这就是典型的一对多关系模型

    1. Post模型

    base table: posts

    字段预设:id标示行主键

    relation method: comments(){return $this->hasMany('AppComment')}

    如果需要覆盖默认命名规约,我们需要这样调用:

    public function comments(){return $this->hasMany('AppComment','foreign_owner_postid_key','local_postid_key')}

    注意这里:foreign_owner_postid_key就是要在comments表中具有的字段名;

    local_postid_key就是posts本表中必须具有的主键字段名

    2. Comment模型

    base table: comments

    字段预设: post_id 作为posts表的外键

    relation method: post(){return $this->belongsTo('AppPost')}

    如果需要覆盖默认命名规约,同样我们需要这样调用:

    public function post(){return $this->belongsTo('AppPost','foreign_owner_postid_key','other_local_postid_key'}

    注意:这里foreign_owner_postid_key就是在本comments表中必须具有的引用posts表的外键字段名;

    other_local_postid_key就是必须在posts表中具有的主键名称。之所以加local,other就是代表的是本表的还是关联表的。

    另外,上面也已经提到由于relationship本身就是query builder因此可以增加约束级联,比如:

    Post::find(1)->comments()->where('title','foo')->first()就只取title为foo的第一条post对应的comment

    other_local_postid_key就是

    注意按照laravel默认命名规约,一对多的关系模型,child model中的owning model

    many 2 many(多对多)

    例子: User belongsToMany Role, Role belongsToMany User

    1. User模型

    base table: users

    字段预设: id主键

    relation method: roles(){return $this->belongsToMany('AppRole')}

    其他预设: role_user pivot表(即两个小写关系之间按照字母排序使用 _ 连接起来)

    2. Role模型

    base table: roles

    字段预设: id主键

    relation method: users(){return $this->belongsToMany('AppUser')}

    其他预设: role_user pivot表(即两个小写关系之间按照字母排序使用 _ 连接起来)

    上面的两个model中都有预设pivot表,我们可以通过传参来覆盖它(注意这里只需要在一个方向上调用即可,不用像上面one 2 many需要两边都这样调用才能work!):

    public function roles(){return $this->belongsToMany('AppRole','user_role','user_pivot_ziduan_name','role_ziduan_name_in_pivot')}

    再看一个使用query builder特性的例子:$roles=AppUser::find(1)->roles()->orderBy('name')->get()

    也可以在访问relation的同时访问pivot表数据:

    public function roles(){$this->belongsToMany('AppRole')->withPivot('column1_in_pivot','c2_in_pivot')}

    foreach ($user->roles as $role){ echo $role->pivot->column1_in_pivot}

    上面代码中获取relation的同时,也返回pivot表格的对应数据,并且可以作为pivot relation来操作数据

    has Many through(通过xx一对多)

    例子:由于Country hasMany User,同时User hasMany Post,所以Country可以hasMany Post via User(注意同时User belongsTo Countery, Post belongsTo User)

    1. Country模型

    base table: countries

    字段预设: id, name

    relation methods: 

    public function users(){return $this->hasMany('AppUser')}

    public function posts(){return $this->hasManyThrough('AppPost')}

    2.User模型

    base table: users

    字段预设: id, country_id, username

    relation method: country(){return $this->belongsTo('AppCountry')}

    3.Post模型

    base table: posts

    字段预设: id, user_id, title,description

    relation method: user(){return $this->belongsTo('AppUser')}

    Polymorphic relation(多态一对多)

    例子:Photo可以morphTo Staff, 同时Photo也可以morphTo Product, Product可以morphMany Photo, Staff也可以morphMany Photo,也就是说一个model可以belongsTo多种parentmodel,多种parentmodel都可以hasMany这个model时,非常适合这种polymorphic relation

    1. Staff模型:

    base table: staffs

    字段预设: id, name

    relation method: photos(){return $this->morphMany('AppPhoto','imagable')} //注意imagable是Photo模型的一个relation method

    2.Product模型

    base table: products

    字段预设: id, name, price

    relation method: photos(){return $this->morphMany('AppPhoto','imagable')}//注意imagable是Photo模型的一个relation method

    3. Photo模型

    base table: photos

    字段预设: id,path,imageable_id,imageable_type //注意imageable就是本模型中的relation method名称,这里imageable_id和imageable_type非常关键,也是laravel根据photos表找到对应photos属于哪种模型的关键,也就是说一张图片到底是staff的图片还是产品product的图片,就看这个type和id了,由type找到是哪张表,id再找到这张表中第几条数据。默认情况下laravel会使用Model的class全称作为type,但是有时你可能并不希望如此,这时,一个可行的方案是创建一个types表,来指定这种对应关系,同时在AppServiceProvider booted方法中调用

    Relation::morphMap($morphMapArray);

    来完成这种人性化的映射关系

    Many 2 Many Polymorphic Relations

    例子: Post可以打上多个Tag标签, Video也可以同样打上多个Tag,也就是说Tag可以同时打在video或者post上。

    如何在model中增加一个不存在于base table字段中的字段?

    很多时候存在这样的场景:你很难找到一个适合的relation来描述两个表格之间的关系,或者你不需要建立复杂的relation,你只需要在你返回的model中添加一条额外的信息,比如,User model中你可能需要一条额外的字段'isAdmin'来方便判断该用户是否admin用户,这时可以这样操作:(但是好像动态访问不是很好用)

    https://laravel.com/docs/5.1/eloquent-serialization#appending-values-to-json

    class User extends Model
    {
        protected $appends = ['is_admin'];
        /**
         * Get the administrator flag for the user.
         *
         * @return bool
         */
        public function getIsAdminAttribute()
        {
            return $this->attributes['admin'] == 'yes';
        }
    }

     laravel relation相关简单调试手段

    虽然laravel的relation非常强大,只要你稍加熟悉,你就能花非常少的effort构建出非常强大的web后端应用来。但是有时候,一些高级的sql查询,laravel可能并未按照我们的预期工作,这时,我们就希望eloquent最终到底映射成了什么sql,有几种方法获取这方面的信息:

    1. get()替换为toSql()直接打印出来;

    $results = User::where(function($q) use ($request) {
        $q->orWhere('email', 'like', '%john@example.org%');
        $q->orWhere('first_name', 'like', '%John%');
        $q->orWhere('last_name', 'like', '%Doe%');
    })->toSql();

    2. listen事件

    DB::listen(function($sql) {
        var_dump($sql);
    });

    https://scotch.io/tutorials/debugging-queries-in-laravel

    查询relation时针对relation实现限制条件:(has, doesnotHave)

    // Retrieve all posts with at least one comment containing words like foo%
    $posts = Post::has('comments.votes')->get(); // 简化版
    $posts = Post::whereHas('comments', function ($query) {
        $query->where('content', 'like', 'foo%');
    })->get();
    
    $posts = AppPost::doesntHave('comments')->get(); // 简化版
    $posts = Post::whereDoesntHave('comments', function ($query) {
        $query->where('content', 'like', 'foo%');
    })->get();

    hasManyThrough 多对多?

    http://laravel.io/forum/03-04-2014-hasmanythrough-with-many-to-many

  • 相关阅读:
    第一个Servlet项目(IDEA)
    Web交互基本流程以及HTTP协议详解
    mybatis中Mapper.xml配置详解
    认识mybatis
    SpringAOP
    Spring AOP
    70. Climbing Stairs
    位运算
    Leetcode分类
    21. Merge Two Sorted Lists
  • 原文地址:https://www.cnblogs.com/kidsitcn/p/5859311.html
Copyright © 2011-2022 走看看