美文网首页laravel核心Laravel
laravel belongsToMany解析

laravel belongsToMany解析

作者: 云龙789 | 来源:发表于2018-08-22 14:02 被阅读70次

    推荐文章深入理解 Laravel Eloquent(三)——模型间关系(关联)

    其实关联模型的效率是最低的,但是我们可以通过关联模型查看更多的 sql语句的写法。

    多对对的本质其实就是两个表使用了inner join table on语句 查询
    比如下面两个图,我们要取出parent_id=9的数据,可以使用

    select B* from system_menu as A  inner join system_menu as B 
    on B.`parent_id`= A.menu_id where A.menu_id=9
    或者 where B.parent_id=9
    但是这样其实没有什么意义,直接where查询是一样的
    
    图片.png
    图片.png

    首先我们要了解几个概念

    user: id ... ... account_id
    account: id ... ... user_id
    

    1.外键,在user表中account_id就是外键。
    外键不在本表内,他是在与本表关联的表里面
    这个字段相当于是account表的id键。

    belongsToMany()多对多这个关联可能不好理解,但是我们可以打开源码,一步步打印

       /**
         * Define a many-to-many relationship.
         *
         * @param  string  $related
         * @param  string  $table
         * @param  string  $foreignPivotKey
         * @param  string  $relatedPivotKey
         * @param  string  $parentKey
         * @param  string  $relatedKey
         * @param  string  $relation
         * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
         */
        public function belongsToMany($related, $table = null, $foreignPivotKey = null, $relatedPivotKey = null,
                                      $parentKey = null, $relatedKey = null, $relation = null)
        {
            // If no relationship name was passed, we will pull backtraces to get the
            // name of the calling function. We will use that function name as the
            // title of this relation since that is a great convention to apply.
            if (is_null($relation)) {
                $relation = $this->guessBelongsToManyRelation();
            }
    
            // First, we'll need to determine the foreign key and "other key" for the
            // relationship. Once we have determined the keys we'll make the query
            // instances as well as the relationship instances we need for this.
            $instance = $this->newRelatedInstance($related);
    
            $foreignPivotKey = $foreignPivotKey ?: $this->getForeignKey();
    
            $relatedPivotKey = $relatedPivotKey ?: $instance->getForeignKey();
    
            // If no table name was provided, we can guess it by concatenating the two
            // models using underscores in alphabetical order. The two model names
            // are transformed to snake case from their default CamelCase also.
            if (is_null($table)) {
                $table = $this->joiningTable($related);
            }
    
            return $this->newBelongsToMany(
                $instance->newQuery(), $this, $table, $foreignPivotKey,
                $relatedPivotKey, $parentKey ?: $this->getKeyName(),
                $relatedKey ?: $instance->getKeyName(), $relation
            );
        }
    

    $related

    `$instance = $this->newRelatedInstance($related);`是我们最终要获取数据的关联表
    

    $table是一个中间表

     // If no table name was provided, we can guess it by concatenating the two
            // models using underscores in alphabetical order. The two model names
            // are transformed to snake case from their default CamelCase also.
            if (is_null($table)) {
                $table = $this->joiningTable($related);
            }
    

    $foreignPivotKey可以看出,其实是本表的外键

    $foreignPivotKey = $foreignPivotKey ?: $this->getForeignKey();
    

    $relatedPivotKey

    $instance = $this->newRelatedInstance($related);
    //打印$instance 得到第一个参数的类
    $relatedPivotKey = $relatedPivotKey ?: $instance->getForeignKey();
    // 所以relatedPivotKey 我个人理解应该是第一个参数类的外键
    可是事实上是 第一个参数类的主键ID
    

    $parentKey第五个参数,如果第三个参数用的不是自己的主键,则需要第五个参数。现在我们使用的是role_id,第五个参数应该就是role_id,虽然从sql语句上看不出来什么,但是你看传递的参数值就知道了,传递的其实就是第五个参数的值

    $parentKey ?: $this->getKeyName(),
    
        public function getKeyName()
        {
            return $this->primaryKey;
        }
    所以第五个参数默认是本地的主键
    

    belongsToMany()这个方法的使用,我感觉文档上解释的并不多,以至于里面的参数感觉有写模糊,不知道写什么,还是自己一步步摸索吧
    我的思路是,参数不填写,会默认显示参数,将默认参数打印,我们就知道写什么了

    • 需求,一个用户表admin里面有role_id字段,
      org_role_permit表菜单menuadmin的映射表

    admin.php模型里面

    return $this->belongsToMany('App\Models\System\Menu', 'org_role_permit', 'role_id', 'menu_id');
    
    得到的sql
    select `system_menu`.*, `org_role_permit`.`role_id` as `pivot_role_id`, 
    `org_role_permit`.`menu_id` as `pivot_menu_id` 
    from `system_menu` inner join `org_role_permit` 
    on `system_menu`.`menu_id` = `org_role_permit`.`menu_id` 
    where `org_role_permit`.`role_id` = 2
    
    • 第三个参数是本地关联的ID,可以理解成本地id,但是并不是所有的关联都是使用ID,所以其实也不能理解成ID。同时他也是where条件里面的一个字段,如果换成menu_id,则会变成 where org_role_permit.menu_id = 2
    图片.png 打印文件.png 打印结果

    在刚开始没有思路的时候,其实知道不适用模型是可以实现的,首先取出关联表里面role_id对应的数据的所有menu_id数组集,然后在menu表里面取出所有menu_id的数据

        $menuIds = \DB::table('org_role_permit')
                ->where('role_id', '=', $this->getRoleId())
                ->pluck('menu_id')->toArray();
                    return Menu::whereIn('menu_id', $menuIds);
    

    但是后来发现一种更简单的方式,直接通过inner join内连接取值即可,因为越少的sql取值速度越快,所以建议使用以下方式。

     return Menu::where('role_id', '=', $this->getRoleId())
           ->join('org_role_permit','system_menu.menu_id','=','org_role_permit.menu_id');
    
    得到的sql
    select * from `system_menu` inner join `org_role_permit` on 
    `system_menu`.`menu_id` = `org_role_permit`.`menu_id` where `role_id` = 2
    
    图片.png

    相关文章

      网友评论

        本文标题:laravel belongsToMany解析

        本文链接:https://www.haomeiwen.com/subject/bezeiftx.html