сократить запрос к базе данных до одного и избежать вызова функции-члена load () при нулевой ошибке - PullRequest
1 голос
/ 15 марта 2019

У меня есть эта функция:

public function show($id)

    {

        if (count($post = Post::find($id))) {

            $post = $post->load(['comments' => function ($q) {
                $q->latest();
                $q->with(['author' => function ($q) {

                    $q->select('id', 'username');

                }]);
            }, 'user' => function ($q) {

                $q->select('id', 'username');

            }]);

            $this->authorize('seePost', $post);

            return view('post.show', ['post' => $post]);

        } else {

            dd('no post');
        }

    }

Я добавил оператор if, как будто я пытаюсь открыть маршрут к несуществующему идентификатору записи, я получаю ошибку Call to a member function load() on null. Однако теперь у меня есть два запроса, один ищет Post в БД, и если он находит один, я должен загрузить отношения со вторым. Что я могу сделать, чтобы вернуться к одному запросу со всеми загруженными отношениями и избежать ошибки? Любая подсказка?

Ответы [ 2 ]

1 голос
/ 15 марта 2019

Вы можете использовать Constraining Eager Loads, сделать это так:

https://laravel.com/docs/5.8/eloquent-relationships#constraining-eager-loads

$post = Post::with(["comments" => function ($query) {
        // Order by created_at, query comment author & select id, username
        $query->latest()->with(["author" => function ($q) {
            $q->select("id", "username");
        }]);

    }, "user" => function ($query) {
        // Query post author & select id,username
        $query->select("id", "username");
    }])

    // Fetch post or throw a 404 if post is missing
    ->findOrFail($id);

    // You can also return an empty post instance like this if post is missing
    // ->findOrNew([]);

    // Or return the post or null if post is missing
    // ->find($id);

    // Authorize
    $this->authorize('seePost', $post);

    return view("post.show", ["post" => $post]);
0 голосов
/ 15 марта 2019

В Laravel есть функция Eager Loading, которая будет полезна в вашем случае.Eager Loading позволяет вам автоматически загружать отношения вместе с тем же запросом, который вы используете для получения основной информации о модели.https://laravel.com/docs/5.8/eloquent-relationships#eager-loading

Вы можете указать следующие коды.

Самый простой способ:

$post = Post::with('comments.author', 'user')
                ->find($id);

Или запрос точной настройки с обратным вызовом:

$post = Post::with(['comments' => function ($q) {
            // if you use comments select, then you need to specify foreign key too
            $q->select('id', 'author_id', 'details') // comment fields
                ->latest(); // Use chaining method
            // OR use $q = $q->latest();
        },
        'comments.author' => function ($q) {
            $q->select('id', 'username'); // author fields
        },
        'user' => function ($) {
            $q->select('id', 'username'); // user fields
        }])
        ->find($id);

В некоторых случаях вам могут потребоваться некоторые модификации, но в целом, чтобы избежать проблемы N+1 запросов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...