laravel belongsToMany解析

推荐文章深入理解 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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352

推荐阅读更多精彩内容

  • 回首页 第一部分 Drupal简介 Drupal overview A tour of Drupal fundam...
    王乂阅读 2,021评论 0 9
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,647评论 18 139
  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,294评论 0 9
  • 作者:华莱士.沃特莱斯 一条公式,三个概念,十大标准帮助你收获100%健康! 这本书从心理学角度讲述了保持健康的方...
    殷琦榕阅读 359评论 0 0
  • 蝉儿在依赖着 大树的胸膛, 撒娇的声音 让人受不了。 过街的熙攘, 耳里播放的, 全是热闹。 洋溢出来的 俱是欢笑...
    混尔清阅读 245评论 0 1