Laravel Eloquent disable automatic eager loading

In the example you provided, the relationship data is "lazy loaded" not "eager loaded". This means the relationship data is not actually loaded until you first access the property.

However, Eloquent can "eager load" relationships at the time you query the parent model. Eager loading alleviates the N + 1 query problem.

To eager load a relationship, you can use eloquent with() method:

$posts = Post::published()->with('author')->get();

Now each post will be eagger loaded with the author model, thus avoiding the N + 1 problem.

You can also specify if you would like to eager load specific columns only:

$posts = Post::published()->with('author:id,name')->get();

And if you want to always load a relationship when retrieving a model, you can define a $with property on the model:

class Post extends Model
{
    /**
     * The relationships that should always be loaded.
     *
     * @var array
     */
    protected $with = ['author'];

    /**
     * Get the author that wrote the book.
     */
    public function author()
    {
        return $this->belongsTo('App\Author');
    }
}

More information: https://laravel.com/docs/6.x/eloquent-relationships#eager-loading


It's pretty simple, just add to your model:

public $preventsLazyLoading = true;

Then if you try to lazy load a relation you will get an error

Illuminate\Database\LazyLoadingViolationException : Attempted to lazy load [<ModelName>] on model [<ModelName>] but lazy loading is disabled.

You can also create a parent class for your models, something like

abstract class Model extends \Illuminate\Database\Eloquent\Model
{
    public $preventsLazyLoading = true;
}

Then extend it in your models and they automatically will disable lazy load.

For Laravel 8 or later versions

There's another way to disable it in app service provide

// app/Providers/AppServiceProvider.php
 
public function boot()
{
    Model::preventLazyLoading(! app()->isProduction());
}

As it says, it will disable lazy load for all environments except production.

Reference


It's lazy load the example you provided as @LobsterBaz mentioned. If you want to avoid that:

You can check if the relationship is loaded

foreach ($posts as $p) { 
    if ($p->relationLoaded('author')) echo $p->author->name; 
}

But I found this package Laravel Disable Lazy Load which has all the credit for the idea.

That is very simple. By borrowing the idea you can create a Trait yourself to do it overriding the getRelationshipFromMethod.

<?php

namespace App\Traits;


trait DisableLazyLoad
{
    public function getRelationshipFromMethod($method)
    {
        throw new \BadMethodCallException('Relation lazy load has been disabled for performance reasons.');
    }
}

Then use the Trait in your Model

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use App\Traits\DisableLazyLoad;

class Post extends Model
{

    use DisableLazyLoad;

}

or install the package an use it in the same way

composer require ybaruchel/laravel-disable-lazyload