Нетерпеливая и ленивая загрузка в Eloquent Laravel

В Eloquent отношения имеют функцию "ленивой загрузки". То есть они загружаются только при обращении к свойствам. Но помимо этого можно "нетерпеливо" загружать отношения во время загрузки родительской модели. Такая загрузка решает проблему N+1 запроса. Продемонстрируем эту проблему.

Нетерпеливая загрузка

Представьте, что есть информация о книгах и метод, которые позволяет получить их авторов:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Book extends Model {
   public function author() {
      return $this->belongsTo('App\Author');
   }
}
?>
Для получения имён авторов используется такой цикл:
<?php
$books = App\Book::all();

foreach ($books as $book) {
   echo $book->author->name;
}
?>
Такой код выполнит 1 запрос, чтобы получить все книги из таблицы. А для получения имени автора будет сделан второй запрос внутри цикла. Таким образом этим кодом будет сделано N+1 запросов к базе (где N - это количество книг).

Чтобы уменьшить количество запросов, можно использовать "нетерпеливую" загрузку. Достаточно добавить метод "with", который добавит один запрос, но избавит от запроса в цикле:
<?php
$books = App\Book::with('author')->get();

foreach ($books as $book) {
   echo $book->author->name;
}
?>
При выполнении такого кода будет сделано только два запроса к базе данных:
select * from books;
select * from authors where id in (1, 2, 3, ...);
В качестве аргумента для метода "with" можно указать сразу несколько отношений:
<?php
$books = App\Book::with('author', 'publisher')->get();
?>
При работе с большими базами данных часто требуется ограничивать возможные выборки различными условиями. Для этого можно передать методу with массив со значением в виде функции, в которой будет ограничена выборка с помощью метода "where":
<?php
$users = App\User::with(['posts' => function ($query) {
   $query->where('title', 'like', '%Best cheese%');
}])->get();
?>
При этом можно использовать и другие методы конструктора запросов помимо "where".

Ленивая загрузка

Иногда требуется загружать отношение только после того, как родительская модель уже получена, имея возможность не делать этого. Делается это с помощью метода "load", который принимает те же параметры, что и "with":
<?php
$books = App\Book::all();
if ($someCondition) { // условие нетерпеливой загрузки
   $books->load('author', 'publisher');
}
?>
Если требуется установить дополнительные ограничения на выборку, то метод "load" (как и "with") принимает массив, в котором указывается функция конструктора запросов:
<?php
$users = App\User::with(['author' => function ($query) {
   $query->orderBy('published_date', 'asc');
}])->get();
?>
Значения массива должны быть экземплярами Closure, которые получают экземпляр запроса.
MouseDC.ru - хостинг, виртуальный хостинг, покупка доменов, проверка доменов, WHOIS, курсы создания сайтов, вебинары по созданию, курсы разработки сайтов, доработка сайтов, сопровождение сайтов, разработка сайтов, техподдержка сайтов
Cмотрите другие статьи:
Была ли статья полезной?
Была ли эта статья полезна? Есть вопрос?
хостинг для сайтов
Закажите недорогой хостинг Заказать

всего от 290 руб