返回顶部
首页 > 资讯 > 精选 >Laravel之模型关联预加载的示例分析
  • 850
分享到

Laravel之模型关联预加载的示例分析

2023-06-14 11:06:27 850人浏览 八月长安
摘要

这篇文章将为大家详细讲解有关Laravel之模型关联预加载的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Laravel学习笔记之模型关联预加载说明:本文主要说明Laravel Eloquent的

这篇文章将为大家详细讲解有关Laravel之模型关联预加载的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

Laravel学习笔记之模型关联预加载

说明:本文主要说明Laravel Eloquent的延迟预加载(Eager Loading),使用延迟预加载来减少MySQL查询次数。同时,作者会将开发过程中的一些截图和代码黏上去,提高阅读效率。

备注:现在有4张表:商家表merchants、商家电话表phones、商家拥有的店铺shops表和店铺里的商品表products。并且关系是:

[    'merchants_phones' => 'one-to-one',    'merchants_shops'  => 'one-to-many',    'shops_products'   => 'one-to-many',]

现在要求做出一个页面以列表形式显示每个店铺,每个店铺块包含店铺信息如标题、包含店铺商家信息如姓名和电话、包含拥有的商品信息如介绍和价格。看看有没有预加载会有什么不同。

开发环境:Laravel5.1+MAMP+PHP7+Mysql5.5

先写个店铺列表页

1.先装上开发插件三件套(具体可参考:Laravel学习笔记之Seeder填充数据小技巧)
不管咋样,先装上开发插件三件套:

composer require barryvdh/laravel-debugbar --devcomposer require barryvdh/laravel-ide-helper --devcomposer require mpociot/laravel-test-factory-helper --dev//config/app.php        Barryvdh\Debugbar\ServiceProvider::class,Mpociot\LaravelTestFactoryHelper\TestFactoryHelperServiceProvider::class,Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,

2.写上表字段、表关联和测试数据填充器Seeder
依次输入指令:

php artisan make:model Merchant -mphp artisan make:model Phone -mphp artisan make:model Shop -mphp artisan make:model Product -m

写上表字段和表关联:

class CreateMerchantsTable extends Migration{        public function up()    {        Schema::create('merchants', function (Blueprint $table) {            $table->increments('id');            $table->string('username')->unique();            $table->string('email')->unique();            $table->string('first_name');            $table->string('last_name');            $table->timestamps();        });    }        public function down()    {        Schema::drop('merchants');    }}class CreatePhonesTable extends Migration{        public function up()    {        Schema::create('phones', function (Blueprint $table) {            $table->increments('id');            $table->integer('number')->unsigned();            $table->integer('merchant_id')->unsigned();            $table->timestamps();            $table->foreign('merchant_id')                ->references('id')                ->on('merchants')                ->onUpdate('cascade')                ->onDelete('cascade');        });    }        public function down()    {        Schema::table('phones', function($table){            $table->dropForeign('merchant_id'); // Drop foreign key 'user_id' from 'posts' table        });        Schema::drop('phones');    }}class CreateShopsTable extends Migration{        public function up()    {        Schema::create('shops', function (Blueprint $table) {            $table->increments('id');            $table->string('name');            $table->string('slug')->unique();            $table->string('site');            $table->integer('merchant_id')->unsigned();            $table->timestamps();            $table->foreign('merchant_id')                ->references('id')                ->on('merchants')                ->onUpdate('cascade')                ->onDelete('cascade');        });    }        public function down()    {        Schema::table('shops', function($table){            $table->dropForeign('merchant_id'); // Drop foreign key 'user_id' from 'posts' table        });        Schema::drop('shops');    }}class CreateProductsTable extends Migration{        public function up()    {        Schema::create('products', function (Blueprint $table) {            $table->increments('id');            $table->string('name');            $table->text('short_desc');            $table->text('long_desc');            $table->double('price');            $table->integer('shop_id')->unsigned();            $table->timestamps();            $table->foreign('shop_id')                ->references('id')                ->on('shops')                ->onUpdate('cascade')                ->onDelete('cascade');        });    }        public function down()    {        Schema::table('products', function($table){            $table->dropForeign('shop_id'); // Drop foreign key 'user_id' from 'posts' table        });        Schema::drop('products');    }}class Merchant extends Model{        public function phone()    {        return $this->hasOne(Phone::class, 'merchant_id');    }        public function shops()    {        return $this->hasMany(Shop::class, 'merchant_id');    }}class Phone extends Model{        public function merchant()    {        return $this->belongsTo(Merchant::class, 'merchant_id');    }}class Product extends Model{        public function shop()    {        return $this->belongsTo(Shop::class, 'shop_id');    }}class Shop extends Model{        public function merchant()    {        return $this->belongsTo(Merchant::class, 'merchant_id');    }        public function products()    {        return $this->hasMany(Product::class, 'shop_id');    }}

别忘了利用下开发三件套输入指令:

php artisan ide-helper:generatephp artisan ide-helper:modelsphp artisan test-factory-helper:generate

表的关系如图:

Laravel之模型关联预加载的示例分析

然后写Seeder,可以参考Laravel学习笔记之Seeder填充数据小技巧:

php artisan make:seeder MerchantTableSeederphp artisan make:seeder PhoneTableSeederphp artisan make:seeder ShopTableSeederphp artisan make:seeder ProductTableSeederclass MerchantTableSeeder extends Seeder{        public function run()    {        $faker = Faker\Factory::create();        $datas = [];        foreach (range(1, 20) as $key => $value) {            $datas[] = [                'username'   =>  $faker->userName ,                'email'      =>  $faker->safeEmail ,                'first_name' =>  $faker->firstName ,                'last_name'  =>  $faker->lastName ,                'created_at' => \Carbon\Carbon::now()->toDateTimeString(),                'updated_at' => \Carbon\Carbon::now()->toDateTimeString()            ];        }        DB::table('merchants')->insert($datas);    }}class PhoneTableSeeder extends Seeder{        public function run()    {        $faker        = Faker\Factory::create();        $merchant_ids = \App\Merchant::lists('id')->toArray();        $datas        = [];        foreach (range(1, 20) as $key => $value) {            $datas[]  = [                'number'      => $faker->randomNumber() ,                'merchant_id' => $faker->randomElement($merchant_ids) ,                'created_at'  => \Carbon\Carbon::now()->toDateTimeString(),                'updated_at'  => \Carbon\Carbon::now()->toDateTimeString()            ];        }        DB::table('phones')->insert($datas);    }}class ShopTableSeeder extends Seeder{        public function run()    {        $faker        = Faker\Factory::create();        $merchant_ids = \App\Merchant::lists('id')->toArray();        $datas        = [];        foreach (range(1, 40) as $key => $value) {            $datas[]  = [                'name'         =>  $faker->name ,                'slug'         =>  $faker->slug ,                'site'         =>  $faker->Word ,                'merchant_id'  =>  $faker->randomElement($merchant_ids) ,                'created_at'   => \Carbon\Carbon::now()->toDateTimeString(),                'updated_at'   => \Carbon\Carbon::now()->toDateTimeString()            ];        }        DB::table('shops')->insert($datas);    }}class ProductTableSeeder extends Seeder{        public function run()    {        $faker    = Faker\Factory::create();        $shop_ids = \App\Shop::lists('id')->toArray();        $datas    = [];        foreach (range(1, 30) as $key => $value) {            $datas[] = [                'name'              =>  $faker->name ,                'short_desc'        =>  $faker->text ,                'long_desc'         =>  $faker->text ,                'price'             =>  $faker->randomFloat() ,                'shop_id'           =>  $faker->randomElement($shop_ids) ,                'created_at'        =>  \Carbon\Carbon::now()->toDateTimeString() ,                'updated_at'        =>  \Carbon\Carbon::now()->toDateTimeString()            ];        }        DB::table('products')->insert($datas);    }}php artisan db:seed

3.写个简单View视图
(1)用Repository Pattern来组织代码

//app/Repositorynamespace App\Repository;interface ShopRepositoryInterface{    public function all();}//app/Repository/Eloquentnamespace App\Repository\Eloquent;use App\Repository\ShopRepositoryInterface;use App\Shop;class ShopRepository implements ShopRepositoryInterface{        public $shop;    public function __construct(Shop $shop)    {        $this->shop = $shop;    }    public function all()    {        // TODO: Implement all() method.        $shops = $this->shop->all();        return $shops;    }}//app/provider/ShopRepositoryServiceProvider//php artisan make:provider ShopRepositoryServiceProvider    public function reGISter()    {        $this->app->bind(ShopRepositoryInterface::class, ShopRepository::class);    }    //app/Http/Controllers/ShopController.phpclass ShopController extends Controller{        public $shop;        public function __construct(ShopRepositoryInterface $shopRepositoryInterface)    {        $this->shop = $shopRepositoryInterface;    }    public function all()    {        $shops = $this->shop->all();        return view('shop.index', compact('shops'));    }}//视图//resources/views/shop/layout.blade.php<html lang="en"><head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1">    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->    <title>Bootstrap Template</title>    <!-- 新 Bootstrap 核心 CSS 文件 -->    <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">    <style>        html,body{            width: 100%;            height: 100%;        }        *{            margin: 0;            border: 0;        }    </style></head><body><p class="container">    <p class="row">        <p class="col-xs-12 col-md-12">            @yield('content')        </p>    </p></p><!-- Jquery文件。务必在bootstrap.min.js 之前引入 --><script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script><!-- 最新的 Bootstrap 核心 javascript 文件 --><script src="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script><script></script></body></html>//resources/views/shop/index.blade.php@extends('shop.layout')@section('content')    <ul class="list-group">        @foreach($shops as $shop)            <li class="list-group-item" style="margin-top: 10px">                <h2><strong style="color: darkred">Store:</strong>{{$shop->name}}</h2>                <span><strong style="color: orangered">Member:</strong>{{$shop->merchant->first_name.' '.$shop->merchant->last_name}}</span>                {{--这里数组取电话号码--}}                <span><strong style="color: orangered">Phone:</strong>{{$shop->merchant->phone['number']}}</span>                <ul class="list-group">                    @foreach($shop->products as $product)                        <li class="list-group-item">                            <h4><strong style="color: red">Name:</strong>{{$product->name}}</h4>                            <h5><strong style="color: red">Desc:</strong>{{$product->short_desc}}</h5>                            <h5><strong style="color: red">Price:</strong>{{$product->price}}</h5>{{--                            {!! Debugbar::info('products:'.$product->id) !!}--}}                        </li>                    @endforeach                </ul>            </li>        @endforeach    </ul>@endsection//路由Route::get('/eagerload', 'ShopController@all');

(2)Debugbar查看程序执行数据
Laravel之模型关联预加载的示例分析

可以看到,执行了121次query,耗时38.89ms,效率很低,仔细观察每一个statement就发现这是先扫描shops表,再根据shops中每一个merchant_id去查找merchants表,查找products表也是这样,又有很多次query,这是N+1查找问题。

预加载查询

(1)嵌套预加载
Eloquent在通过属性访问关联数据时是延迟加载的,就是只有该关联数据只有在通过属性访问它时才会被加载。在查找上层模型时可以通过预加载关联数据,避免N+1问题。而且,使用预加载超级简单。
只需修改一行:

//app/Repository/Eloquent/ShopRepository    public function all()    {        // TODO: Implement all() method.//        $shops = $this->shop->all();        //通过`点`语法嵌套预加载,多种关联就写对应的关联方法        //Shop这个Model里关联方法是Merchant()和Products(),Merchant Model里关联方法是Phone()        $shops = $this->shop->with(['merchant.phone', 'products'])->get();        return $shops;    }

不需要修改其他代码,再看Debugbar里的查询:

It is working!!!

发现:只有4个query,耗时3.58ms,效率提高很多。把原来的N+1这种query改造成了where..in..这种query,效率提高不少。可以用EXPLAIN来查看sql语句的执行计划。

(2)预加载条件限制
还可以对预加载进行条件限制,如对products进行预先排序,代码也很好修改,只需:

//app/Repository/Eloquent/ShopRepositorypublic function all()    {        // TODO: Implement all() method.//        $shops = $this->shop->all();//        $shops = $this->shop->with(['merchant.phone', 'products'])->get();        $shops = $this->shop->with(['members.phone', 'products'=>function($query){//            $query->orderBy('price', 'desc');            $query->orderBy('price', 'asc');        }])->get();        return $shops;    }

通过加个限制条件,就等于在预加载products时SQL语句上加个排序。

关于“Laravel之模型关联预加载的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

--结束END--

本文标题: Laravel之模型关联预加载的示例分析

本文链接: https://lsjlt.com/news/270242.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Laravel之模型关联预加载的示例分析
    这篇文章将为大家详细讲解有关Laravel之模型关联预加载的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Laravel学习笔记之模型关联预加载说明:本文主要说明Laravel Eloquent的...
    99+
    2023-06-14
  • laravel多对多关联模型的示例分析
    这篇文章给大家分享的是有关laravel多对多关联模型的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。关联模型(多对多)多对多关系(抽象)例:一篇文章可能有多个关键词,一个关键词可能被多个文章使用。 关键...
    99+
    2023-06-20
  • Three.js加载外部模型的示例分析
    这篇文章主要介绍了Three.js加载外部模型的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1.  首先我们要在官网: ...
    99+
    2024-04-02
  • javascript模块加载器的示例分析
    这篇文章将为大家详细讲解有关javascript模块加载器的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。定义var MyModules =&...
    99+
    2024-04-02
  • CommonJS中模块加载的示例分析
    这篇文章主要介绍CommonJS中模块加载的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!叨叨一会CommonJSCommon这个英文单词的意思,相信大家都认识,我记得有一个...
    99+
    2024-04-02
  • swoole之进程模型的示例分析
    小编给大家分享一下swoole之进程模型的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!初识server一文的时候我们说过,swoole是事件驱动的。在使...
    99+
    2023-06-14
  • Entity Framework 4.0自关联建模的示例分析
    这篇文章主要介绍了Entity Framework 4.0自关联建模的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。针对这个表建立自关联,详细截图如下Children...
    99+
    2023-06-17
  • HTML5中资源预加载Link prefetch的示例分析
    小编给大家分享一下HTML5中资源预加载Link prefetch的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!不管是...
    99+
    2024-04-02
  • Angular2中模块懒加载的示例分析
    这篇文章主要介绍了Angular2中模块懒加载的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。当项目变得复杂庞大以后,如果所有页面都...
    99+
    2024-04-02
  • java之JVM架构模型的示例分析
    小编给大家分享一下java之JVM架构模型的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Java可以用来干什么Java主要应用于:1. web开发;2....
    99+
    2023-06-14
  • js简易模块加载器的示例分析
    这篇文章主要为大家展示了“js简易模块加载器的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“js简易模块加载器的示例分析”这篇文章吧。前端模块化关注前端...
    99+
    2024-04-02
  • Angular中模块和懒加载的示例分析
    这篇文章主要介绍Angular中模块和懒加载的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、Angular 内置模块二、Angular 自定义模块当我们项目比较小的时候可以不用自定义模块。但是当我们项目非...
    99+
    2023-06-06
  • Java虚拟机之类加载的示例分析
    小编给大家分享一下Java虚拟机之类加载的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序...
    99+
    2023-06-15
  • JVM系列之内存模型的示例分析
    这篇文章主要介绍JVM系列之内存模型的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1. 内存模型和运行时数据区这一章学习java虚拟机内存模型(Java Virtual machine menory mod...
    99+
    2023-06-15
  • java类加载的示例分析
    这篇文章将为大家详细讲解有关java类加载的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1、说明当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过以下三个步骤对该类进行初始化。2、...
    99+
    2023-06-15
  • Javarscript中模块、加载与捆绑的示例分析
    这篇文章给大家分享的是有关Javarscript中模块、加载与捆绑的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。JS模块简介js模块化,简单说就是将系统或者功能分隔成单...
    99+
    2024-04-02
  • css盒模型的示例分析
    小编给大家分享一下css盒模型的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧! 1.各种盒模型 inline-blo...
    99+
    2024-04-02
  • Java设计模式之行为型模式的示例分析
    这篇文章主要介绍Java设计模式之行为型模式的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、行为型模式行为型模式关注点在于"如何运行对象/类";行为型模式用来描述程序在运行时复杂的流程...
    99+
    2023-06-15
  • PHP中关联数组的示例分析
    这篇文章主要为大家展示了“PHP中关联数组的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“PHP中关联数组的示例分析”这篇文章吧。PHP 关联数组关联数...
    99+
    2024-04-02
  • Java内存模型之重排序的示例分析
    小编给大家分享一下Java内存模型之重排序的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一、数据依赖性如果两个操作访问同一个变量,而且这两个操作中有一个操作为写操作,此时这两个操作之间存在数据依赖性。数据依赖性分...
    99+
    2023-06-15
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作