Исключение LazyLoadingViolationException
Исключение LazyLoadingViolationException выбрасывается Eloquent ORM
в Laravel, когда происходит попытка ленивой загрузки связанных данных,
а функция ленивой загрузки отключена в настройках модели. Это исключение
помогает разработчику контролировать количество запросов к базе данных
и избегать проблемы N+1.
Причины возникновения
Исключение возникает, когда к модели применяется метод preventLazyLoading.
Этот метод может быть вызван глобально в сервис-провайдере или локально
в конкретной модели. При доступе к связанной модели через свойство
(например, $user->posts) без предварительной жадной загрузки
будет выброшено исключение.
Синтаксис
<?php
use Illuminate\Database\Eloquent\Model;
// Глобальное отключение ленивой загрузки
Model::preventLazyLoading();
// Локальное отключение в модели
class User extends Model
{
protected static function booted()
{
static::preventLazyLoading();
}
}
?>
Пример возникновения исключения
Рассмотрим ситуацию, когда ленивая загрузка отключена, а мы пытаемся обратиться к связанной модели без жадной загрузки:
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
class UserController extends Controller
{
public function index()
{
Model::preventLazyLoading();
$users = User::all();
foreach ($users as $user) {
foreach ($user->posts as $post) {
echo $post->title;
}
}
}
}
?>
Результат выполнения кода:
"LazyLoadingViolationException: Attempted to lazy load [posts] on model [App\Models\User]"
Пример исправления с жадной загрузкой
Чтобы избежать исключения, необходимо использовать жадную загрузку
с помощью метода with:
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
class UserController extends Controller
{
public function index()
{
Model::preventLazyLoading();
$users = User::with('posts')->get();
foreach ($users as $user) {
foreach ($user->posts as $post) {
echo $post->title;
}
}
}
}
?>
Результат выполнения кода:
"Post 1"
"Post 2"
"Post 3"
Пример локального отключения в модели
Можно отключить ленивую загрузку только для конкретной модели,
используя метод booted:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected static function booted()
{
static::preventLazyLoading();
}
public function posts()
{
return $this->hasMany(Post::class);
}
}
?>
Пример проверки режима разработки
Рекомендуется включать защиту только в среде разработки для обнаружения проблем N+1:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Eloquent\Model;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
if ($this->app->environment('local')) {
Model::preventLazyLoading();
}
}
}
?>
Смотрите также
-
исключение
ModelNotFoundException,
которое возникает при отсутствии модели в базе данных -
исключение
MassAssignmentException,
которое выбрасывается при массовом заполнении неразрешённых полей -
исключение
QueryException,
которое возникает при ошибках выполнения SQL-запросов -
исключение
RelationNotFoundException,
которое выбрасывается при попытке загрузить несуществующую связь