Xopus

Main Menu

  • Schemas
  • CSS
  • Chrome
  • Firefox
  • Fund

Xopus

Header Banner

Xopus

  • Schemas
  • CSS
  • Chrome
  • Firefox
  • Fund
Schemas
Home›Schemas›Disable eloquent lazy loading during development

Disable eloquent lazy loading during development

By Warren B. Obrien
May 21, 2021
0
0



In the next version of Laravel 8, you can strictly disable lazy loading, which results in an exception:

Strict to avoid N + 1 query problems? @themsaidThe recent contribution of the structure to the framework allows you to completely disable deferred loading (an exception will be thrown) …

Can deactivate it only in case of non-production so that the production does not crash if we slip! 💅

Shipped next week! pic.twitter.com/5Q9YpCLRze

– Taylor Otwell 🪐 (@taylorotwell) May 19, 2021

Preventing lazy loading in development can help you find N + 1 bugs earlier in the development process. The Laravel ecosystem has different tools to identify N + 1 requests. However, this approach brings the problem to the fore by throwing an exception.

Demo

Let’s go over this feature very quickly by creating a development version of the framework. 8.x branch because this feature is not yet available at the time of writing. Once published, you will have this feature without going to the last one 8.x plugged.

Install

Start by creating a new app:

laravel new strict-lazy-demo

Then we will update the laravel/framework version in composer.json to make sure we have this functionality (if you try it before the next version) by adjusting the version to 8.x-dev:

{
    "require": {
        "laravel/framework": "8.x-dev"
    }
}

Then run composer update to make sure you get the latest code for this branch:

composer update laravel/framework

At this point, you need to configure your preferred database. I like to run a local MySQL instance using Laravel’s default settings root user without password. I find it convenient to use the default .env values ​​locally to start quickly without any configuration.

mysql -uroot -e"create database strict_lazy_demo"

Once you have configured the database of your choice, make sure you can migrate:

php artisan migrate:fresh

Demonstration data

We will create a Post model and define a one-to-many relation of the User model to demonstrate this functionality. We will start by creating the Post template and accompanying files:

# Create a model with migration and factory
php artisan make:model -mf Post

First, let’s define our Post migration and factory configuration:

// Your filename will differ based on when you create the file.
// 2021_05_21_000013_create_posts_table.php

Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->foreignIdFor(AppModelsUser::class);
    $table->string('title');
    $table->longText('body');
    $table->timestamps();
});

Then set your PostFactory definition method based on the diagram above:

/**
 * Define the model's default state.
 *
 * @return array
 */
public function definition()
{
    return [
        'user_id' => AppModelsUser::factory(),
        'title' => $this->faker->sentence(),
        'body' => implode("nn", $this->faker->paragraphs(rand(2,5))),
    ];
}

Finally, open the DatabaseSeeder file and add the following in the run() method:

/**
 * Seed the application's database.
 *
 * @return void
 */
public function run()
{
    AppModelsUser::factory()
        ->has(AppModelsPost::factory()->count(3))
        ->create()
    ;
}

Pairing models and preventing lazy loading

Now that we have created the migration, planter, and model, we are ready to associate a user with the Post model to demonstrate this functionality.

Add the following method to the User template to give the user an association with the messages:

// app/Models/User.php
/**
 * @return IlluminateDatabaseEloquentRelationsHasMany
 */
public function posts()
{
    return $this->hasMany(Post::class);
}

With that in place, we can migrate and seed the database:

php artisan migrate:fresh --seed

If all went well, we should see something like the following in the console:

We can now use tinker to inspect our predefined data and relationships:

php craftsman tinker >>> $ user = User :: first () => App  Models  User {# 4091 id: 1, name: "Nedra Hayes", email: "[email protected]", email_verified_at: "2021-05-21 00:35:59", created_at: "2021-05-21 00:35:59", updated_at: "2021-05-21 00:35:59",} >>> $ user- > posts => Illuminate  Database  Eloquent  Collection {# 3686 all: [
       AppModelsPost {#3369
         id: 1,
...

The $user->posts property actually calls the database, thus is “lazy” but is not optimized. The convenience of lazy-loading is nice, but it can come with heavy performance burdens in the long-term.

Disabling Lazy Loading

Now that we have the models set up, we can disable lazy loading across our application. You’d likely want to only disable in non-production environments, which is easy to achieve! Open up the AppServiceProvider class and add the following to the boot() method:

// app/Providers/AppServiceProvider.php

public function boot()
{
    Model::preventLazyLoading(! app()->isProduction());
}

If you run a php artisan tinker session again, this time you should get an exception for a lazy loading violation:

php artisan tinker

>>> $user = AppModelsUser::first()
=> AppModelsUser {#3685
     id: 1,
     name: "Nedra Hayes",
     email: "[email protected]",
     email_verified_at: "2021-05-21 00:35:59",
     #password: "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi",
     #remember_token: "jHSxFGKOdw",
     created_at: "2021-05-21 00:35:59",
     updated_at: "2021-05-21 00:35:59",
   }
>>> $user->posts
IlluminateDatabaseLazyLoadingViolationException with message
'Attempted to lazy load [posts] on model [AppModelsUser] but lazy loading is disabled.  '

If you want to see what happens if you use lazy loading to a view file, change the default route as follows:

Route::get("https://laravel-news.com/", function () {
    return view('welcome', [
        'user' => AppModelsUser::first()
    ]);
});

Then add the following somewhere in the welcome.blade.php deposit:

Posts

@foreach($user->posts as $post)

{{ $post->title }}

{{ $post->body }}

@endforeach

If you load your app through Valet or artisan serve, you should see something like the following error page:

Although you get exceptions during development, accidental deployment of code that triggers a lazy load will continue to work as long as you set up environment verification correctly in the service provider.

Learn more

You can learn how this feature was implemented: 8.x Add Eloquent Strict Loading Mode – Pull Request # 37363. Many thanks to Mohamed Said, the contributors, and of course Taylor Otwell for adding the polish to disable the lazy loading conditionally.





Related posts:

  1. Biden administration signals sweeping shift in focus to deal with cyber concerns in government procurement Baker Donelson
  2. My five # 436 | Inbound Marketing Agency
  3. Spring Boot Tutorial Brian Matthews
  4. ChaosSearch Data Platform Now Available in the AWS Marketplace

Recent Posts

  • This Keyboard Shortcut Can Undo Your Most Annoying Browser Mistake
  • UCSF and I-SPY 2 breast cancer researchers develop newly redefined breast cancer response subtypes
  • India-based web design company promises free food to children in need
  • Global Chromium Powder Market Size 2022 Booming By Share, Growth Size, Scope, Key Segments And Forecast To 2029 – Industrial Computing
  • Google Search Adds Author Markup Best Practices

Archives

  • June 2022
  • May 2022
  • April 2022
  • March 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • July 2021
  • June 2021
  • May 2021
  • April 2021
  • March 2021

Categories

  • Chrome
  • CSS
  • Firefox
  • Fund
  • Schemas
  • Terms and Conditions
  • Privacy Policy