查看 Eloquent 模型关联时执行的 SQL 语句

本文目的是查看 Eloquent 在执行模型关联时运行的 SQL 语句

环境

  • PHP 7
  • Laravel 5.1

简介

数据表之间经常会互相进行关联。例如,一篇博客文章可能会有多条评论,或是一张订单可能对应一个下单客户。Eloquent 让管理和处理这些关联变得很容易,同时也支持多种类型的关联:

  • 一对一
  • 一对多
  • 多对多
  • 远层一对多
  • 多态关联
  • 多态多对多关联

接下来,我会根据公司项目的数据库结构,进行举例说明

准备

新增控制器

php artisan make:controller EloquentController

新增路由

Route::get('/', function () {
    return view('welcome');
});

// 一对一
Route::get('eloquent/one-to-one', [
    'as'   => 'eloquent.one.to.one',
    'uses' => 'EloquentController@oneToOne',
]);

// 一对多
Route::get('eloquent/one-to-many', [
    'as'   => 'eloquent.one.to.many',
    'uses' => 'EloquentController@oneToMany',
]);

// 多对多
Route::get('eloquent/many-to-many', [
    'as'   => 'eloquent.many.to.many',
    'uses' => 'EloquentController@manyToMany',
]);

// 远程一对多
Route::get('eloquent/has-many-through', [
    'as'   => 'eloquent.has.many.through',
    'uses' => 'EloquentController@hasManyThrough',
]);

// 多态关联
Route::get('eloquent/polymorphic-relations', [
    'as'   => 'eloquent.polymorphic.relations',
    'uses' => 'EloquentController@polymorphicRelations',
]);

// 多对多多态管理
Route::get('eloquent/many-to-many-polymorphic-relations', [
    'as'   => 'eloquent.many.to.many.polymorphic.relations',
    'uses' => 'EloquentController@manyToManyPolymorphicRelations',
]);

一对一

场景是如每一名加盟商都对应着一份加盟商配置

新增模型

php artisan make:model Models/League
php artisan make:model Models/LeagueConfig

League 模型添加代码如下

// League.php 一名加盟商有一份配置
public function config()
{
    return $this->hasOne('App\Models\LeagueConfig');
}

LeagueConfig 模型添加代码如下

// LeagueConfig.php 一份配置对应一名加盟商
public function league()
{
    return $this->hasOne('App\Models\League');
}

控制器新增代码如下

public function oneToOne(Request $request)
{
    DB::enableQueryLog();
    $data = League::find(8)->config;
    foreach (DB::getQueryLog() as $sql) {
        dump($sql['query']);
    }
    dump($data);
}

查看 SQL

SELECT
    *
FROM
    `z_league`
WHERE
    `z_league`.`id` = 8
LIMIT 1;


SELECT
    *
FROM
    `z_leagueconfig`
WHERE
    `z_leagueconfig`.`league_id` = 8
AND `z_leagueconfig`.`league_id` IS NOT NULL
LIMIT 1;

一对多

场景是仓库一种 SKU 的水果能被多名加盟商进货

新增模型

php artisan make:model Models/Product
php artisan make:model Models/ProductLeague

Product 模型中添加代码

 public function league()
{
    return $this->hasMany('App\Models\ProductLeague', 'pid');
}

控制器新增代码如下:

 public function oneToMany(Request $request)
{
    DB::enableQueryLog();
    $data = Product::find(3062)->league;
    foreach (DB::getQueryLog() as $sql) {
        dump($sql['query']);
    }

    dump($data);
}

查看 SQL

SELECT
    *
FROM
    `z_product`
WHERE
    `z_product`.`id` = 3062
LIMIT 1;

SELECT
    *
FROM
    `z_productleague`
WHERE
    `z_productleague`.`pid` = 3062
AND `z_productleague`.`pid` IS NOT NULL;

多对多

场景是一名用户使用多张不同种类的优惠券,一种优惠券被不同的用户使用

新增模型

php artisan make:model Models/User
php artisan make:model Models/Voucher
php artisan make:model Models/VoucherRecord

User 模型添加代码如下

public function voucher()
{
    return $this->belongsToMany('App\Models\Voucher', 'z_voucher_record', 'uid', 'vid');
}

Voucher 模型添加代码如下

public function user()
{
    return $this->belongsToMany('App\Models\User', 'z_voucher_record', 'vid', 'uid');
}

控制器新增代码如下

public function manyToMany(Request $request)
{
    DB::enableQueryLog();
    $vouchers = User::find(412115)->voucher;
    foreach (DB::getQueryLog() as $sql) {
        dump($sql['query']);
    }
    dump($vouchers);

    DB::enableQueryLog();
    $user = Voucher::find(395)->user;
    foreach (DB::getQueryLog() as $sql) {
        dump($sql['query']);
    }
    dump($user);
}

查看 SQL

# 查询 ID 为 42115 的用户使用过的优惠券
SELECT
    *
FROM
    `z_user`
WHERE
    `z_user`.`id` = 412115;

LIMIT 1 SELECT
    `z_voucher`.*, `z_voucher_record`.`uid` AS `pivot_uid` ,
    `z_voucher_record`.`vid` AS `pivot_vid`
FROM
    `z_voucher`
INNER JOIN `z_voucher_record` ON `z_voucher`.`id` = `z_voucher_record`.`vid`
WHERE
    `z_voucher_record`.`uid` = 412115;

# 查询 ID 为 395 的优惠券被哪些用户使用过

SELECT
    *
FROM
    `z_voucher`
WHERE
    `z_voucher`.`id` = 395;

LIMIT 1 SELECT
    `z_user`.*, `z_voucher_record`.`vid` AS `pivot_vid` ,
    `z_voucher_record`.`uid` AS `pivot_uid`
FROM
    `z_user`
INNER JOIN `z_voucher_record` ON `z_user`.`id` = `z_voucher_record`.`uid`
WHERE
    `z_voucher_record`.`vid` = 395;

远程一对多

新增模型

php artisan make:model Models/Order

Order 模型新增代码如下

 public function order()
{
    return $this->hasManyThrough('App\Models\Order', 'App\Models\User', 'league_id', 'uid');
}

控制器新增代码如下

public function hasManyThrough(Request $request)
{
    DB::enableQueryLog();
    $data = League::find(20)->order;
    foreach (DB::getQueryLog() as $sql) {
        dump($sql['query']);
    }

    dump($data);
}

查看 SQL

# 查询 ID 为 20 的加盟商旗下用户的商品订单
SELECT
    *
FROM
    `z_league`
WHERE
    `z_league`.`id` = 20
LIMIT 1;

SELECT
    `z_order`.*, `z_user`.`league_id`
FROM
    `z_order`
INNER JOIN `z_user` ON `z_user`.`id` = `z_order`.`uid`
WHERE
    `z_user`.`league_id` = 20;

多态关联

新增模型如下

php artisan make:model Models/Staff
php artisan make:model Models/photos
php artisan make:model Models/Products

控制器新增代码如下

public function polymorphicRelations(Request $request)
{
    DB::enableQueryLog();
    $staff = Staff::find(8)->photos;
    foreach (DB::getQueryLog() as $sql) {
        dump($sql['query']);
    }

    dump($staff);

    DB::enableQueryLog();
    $products = Products::find(1)->photos;
    foreach (DB::getQueryLog() as $sql) {
        dump($sql['query']);
    }

    dump($products);
}

查看 SQL

# 查看 ID 为 8 的职员的所有照片
SELECT
    *
FROM
    `eloquent_staff`
WHERE
    `eloquent_staff`.`id` = 8
LIMIT 1;

SELECT
    *
FROM
    `eloquent_photos`
WHERE
    `eloquent_photos`.`imageable_id` = 8
AND `eloquent_photos`.`imageable_id` IS NOT NULL
AND `eloquent_photos`.`imageable_type` = "App\Models\Staff";

# 查看 ID 为 1 的产品的所有图片
SELECT
    *
FROM
    `eloquent_products`
WHERE
    `eloquent_products`.`id` = 1
LIMIT 1;

SELECT
    *
FROM
    `eloquent_photos`
WHERE
    `eloquent_photos`.`imageable_id` = 1
AND `eloquent_photos`.`imageable_id` IS NOT NULL
AND `eloquent_photos`.`imageable_type` = "App\Models\Products";

多态多对多关联

新增模型如下

php artisan make:model Models/Tag
php artisan make:model Models/Post
php artisan make:model Models/Video

控制器新增代码如下

public function manyToManyPolymorphicRelations(Request $request)
{
    DB::enableQueryLog();
    $post_tags = Post::find(8)->tags;
    foreach (DB::getQueryLog() as $sql) {
        dump($sql['query']);
    }

    dump($post_tags);

    DB::enableQueryLog();
    $video_tags = Video::find(8)->tags;
    foreach (DB::getQueryLog() as $sql) {
        dump($sql['query']);
    }

    dump($video_tags);

    DB::enableQueryLog();
    $posts = Tag::find(4)->posts;
    foreach (DB::getQueryLog() as $sql) {
        dump($sql['query']);
    }

    dump($posts);

    DB::enableQueryLog();
    $videos = Tag::find(4)->videos;
    foreach (DB::getQueryLog() as $sql) {
        dump($sql['query']);
    }

    dump($videos);
}

查看 SQL

# 查询 ID 为 8 的文章所使用的标签
SELECT
    *
FROM
    `eloquent_posts`
WHERE
    `eloquent_posts`.`id` = 8
LIMIT 1;

SELECT
    `eloquent_tags`.*, `eloquent_taggables`.`taggable_id` AS `pivot_taggable_id` ,
    `eloquent_taggables`.`tag_id` AS `pivot_tag_id`
FROM
    `eloquent_tags`
INNER JOIN `eloquent_taggables` ON `eloquent_tags`.`id` = `eloquent_taggables`.`tag_id`
WHERE
    `eloquent_taggables`.`taggable_id` = 8
AND `eloquent_taggables`.`taggable_type` = "App\Models\Post";

# 查询 ID 为 8 的视频所使用的标签
SELECT
    *
FROM
    `eloquent_videos`
WHERE
    `eloquent_videos`.`id` = 8
LIMIT 1;

SELECT
    `eloquent_tags`.*, `eloquent_taggables`.`taggable_id` AS `pivot_taggable_id` ,
    `eloquent_taggables`.`tag_id` AS `pivot_tag_id`
FROM
    `eloquent_tags`
INNER JOIN `eloquent_taggables` ON `eloquent_tags`.`id` = `eloquent_taggables`.`tag_id`
WHERE
    `eloquent_taggables`.`taggable_id` = 8
AND `eloquent_taggables`.`taggable_type` = "App\Models\Video";

# 查询 ID 为 4 的标签下的文章
SELECT
    *
FROM
    `eloquent_tags`
WHERE
    `eloquent_tags`.`id` = 4
LIMIT 1;

SELECT
    `eloquent_posts`.*, `eloquent_taggables`.`tag_id` AS `pivot_tag_id` ,
    `eloquent_taggables`.`taggable_id` AS `pivot_taggable_id`
FROM
    `eloquent_posts`
INNER JOIN `eloquent_taggables` ON `eloquent_posts`.`id` = `eloquent_taggables`.`taggable_id`
WHERE
    `eloquent_taggables`.`tag_id` = 4
AND `eloquent_taggables`.`taggable_type` = "App\Modes\Post";

# 查询 ID 为 4 的标签下的视屏

SELECT
    *
FROM
    `eloquent_tags`
WHERE
    `eloquent_tags`.`id` = 4
LIMIT 1;

SELECT
    `eloquent_videos`.*, `eloquent_taggables`.`tag_id` AS `pivot_tag_id` ,
    `eloquent_taggables`.`taggable_id` AS `pivot_taggable_id`
FROM
    `eloquent_videos`
INNER JOIN `eloquent_taggables` ON `eloquent_videos`.`id` = `eloquent_taggables`.`taggable_id`
WHERE
    `eloquent_taggables`.`tag_id` = 4
AND `eloquent_taggables`.`taggable_type` = "App\Models\Video";
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,397评论 25 707
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,560评论 18 399
  • yj yj61949
    Emily的麻麻阅读 306评论 0 0
  • 让人绝望的不是现实,而是期待与现实的落差。随着互联网的发展,信息传播越来越快,人们互相共享生活的程度越来越高,但是...
    花花骚年阅读 202评论 0 1