بهینه سازی روابط در لاراول با Eager loading

دسته بندی: لاراول
زمان مطالعه: 8 دقیقه
۰۲ آذر ۱۳۹۹

یکی از امکانات مهم در لاراول، قابلیت Eager Loading است. از طریق این قابلیت می‌توانیم کوئری‌های بهینه‌تری پیاده سازی کنیم تا در زمان دریافت اطلاعات از دیتابیس صرفه‌جویی کنیم. این کار باعث ارتقاء سرعت برنامه و همچنین دریافت نکردن اطلاعات اضافی در هنگام بارگذاری اطلاعات می‌شود. می‌توانیم فقط اطلاعاتی که نیاز داریم را دریافت کنیم و مشکلاتی از قبیل N+1 را رفع کنیم. در ادامه، بهینه سازی روابط در لاراول با Eager loading را با یک مثال عملی به شما نشان می‌دهیم با ما همراه باشید..

فهرست محتوای این مقاله

چرا برنامه نویسان از Eager loading در برنامه نویسی استفاده نمی‌کنند؟

شاید یکی از مهم‌ترین سؤالاتی که برای شما پیش آمده باشد این است که چرا برنامه نویسان معدودی از امکان Eager loading در لاراول استفاده می‌کنند؟ همان‌طور که می‌دانید یکی از غنی‌ترین منابعی که برای یادگیری فریم ورک لاراول وجود دارد، سایت اصلی این فریم ورک می‌باشد و بسیاری از برنامه نویسانی که از این فریم ورک برای برنامه نویسی استفاده می‌کنند برنامه نویسی با فریم ورک لاراول را از این سایت یاد می‌گیرند. اما در سایت اصلی فریم ورک لاراول توضیحات چندانی راجع به Eager loading در لاراول داده نشده است. (در نسخه‌ی جدید آن یعنی 7.12 به طور کامل‌تری توضیح داده شده است) به همین علت بسیاری از برنامه نویسان نتوانسته‌اند این موضوع را درک کنند و همین عامل باعث شده است که لزوم یادگیری و استفاده از آن را در برنامه‌هایی که می‌نویسند درک نکنند، به همین علت در این مطلب قصد داریم توضیحاتی راجع به استفاده از این ابزار ارائه دهیم.

بهینه سازی روابط در لاراول با Eager loading

خطای رایج N+1 چیست؟

قبل از این که بخواهیم در رابطه با Eager loading در لاراول صحبت کنیم بهتر است با خطای رایج N+1 آشنا شویم. یکی از معمول‌ترین خطاها در حین برنامه نویسی با فریم ورک لاراول، خطای N+1 می‌باشد. این خطا زمانی رخ می‌دهد که برنامه نویس یک رکورد مشخص را واکشی کرده و به دنبال آن فریم ورک لاراول خود به خود N کوئری را به اجرا در می‌آورد که دلیل این کار این است که فریم ورک لاراول قصد دارد رابطه‌های بین جدول‌ها را از روی بانک اطلاعاتی به اجرا در بیاورد. در ادامه قصد داریم یک مثال واضح و آسان درباره‌ی این موضوع ارائه دهیم که به طور کامل متوجه این موضوع شوید.

بهینه سازی روابط در لاراول با Eager loading

مثالی برای خطای N+1

فرض کنید در طول برنامه نویسی با فریم ورک لاراول دو مدل را ایجاد کرده‌اید، مدل اول با نام student و مدل دوم با نام book ایجاد شده است، رابطه‌ای که بین این دو جدول وجود دارد به این صورت است که هر دانش آموز می‌تواند چند کتاب داشته باشد. همان‌طور که می‌دانید برای این کار تنها کافی است یک رابطه بین مدل students و book ایجاد کنیم:

public function books(){

    $this->hasMany(Book::class);

}

حال برای دریافت اطلاعات تنها کافی است کدهای زیر را وارد کنید:

$students = Student::all();

foreach( $students as $student ) {

    $studentName = $student->name;

    $books = $student->books;

}

همان‌طور که مشاهده می‌کنید در این مثال تمامی اطلاعات دانش آموزان دریافت می‌شود و بعد از آن N کوئری دیگر نیز اطلاعات کتاب‌ها را به صورت تک تک دریافت می‌کنند که این در واقع همان خطای N+1 است که در صورت بزرگ بودن جداول می‌تواند وب سایت شما را به خطر بیاندازد. در ادامه به بررسی یک روش بسیار جالب که همان استفاده از Eager loading در لاراول می‌باشد خواهیم پرداخت تا بتوانید این مشکل را حل کنید.

بهینه سازی روابط در لاراول با Eager loading

Eager loading در لاراول چیست؟

Eager loading در لاراول در واقع راه حلی بسیار مناسب برای از بین بردن خطای N+1 در برنامه نویسی می‌باشد. در واقع Eager loading در لاراول راه حلی بسیار مناسب را به شما پیشنهاد می‌دهد که به کمک آن می‌توانید خطای N+1 را که در مثال قبلی توضیح دادیم حل کنید. برای این که بهتر با مفهوم Eager loading در لاراول آشنا شوید بهتر است این مفهوم را نیز با یک مثال به صورت کامل توضیح دهیم.

بهینه سازی روابط در لاراول با Eager loading

یک مثال از Eager Loading در لاراول

در این مطلب قصد داریم مثالی را برای این مورد ارائه دهیم:

$sudents = Student::with('books')->get();

foreach( $students as $student ) {

    $studentName = $student->name;

    $books = $student->book

}

همان‌طور که می‌دانید لاراول با استفاده از دستور with متوجه می‌شود که باید به صورت همزمان اطلاعات را از لیستی که نام دانش آموزان در آن قرار دارد دریافت کرده و به نمایش در بیاورد، از آن جایی که لاراول دارای معماری ORM می‌باشد، تنها دو کوئری را دریافت می‌کند. همان‌طور که می‌توانید در این مورد مشاهده کنید، استفاده از Eager loading در لاراول روش بسیار بهینه‌‌تری نسبت به سایر روش‌ها ( که یکی از آن‌ها را در قسمت قبلی بیان کردیم ) می‌باشد.

لود کردن روابط بیشتر با Eager loading در لاراول

فرض کنید که می‌خواهید از اطلاعات تمامی کلاس‌هایی که یک دانش آموز خاص در آن قرار دارد باخبر شوید. در این صورت می‌توانید از قطعه کد زیر برای این کار استفاده کنید:

$students = Student::with( [ 'books', 'classes'] )->get();

foreach( $students as $student ) {

    $studentName = $student->name;

    $books = $student->books;
    $classes = $student->classes;

}

روابط تو در تو

اگر برای هر کلاس، چند معلم را تعریف کرده باشیم و نیاز باشد که به رابطه‌ی بین کلاس و معلم هم دسترسی داشته باشیم، می‌توانیم به شکل زیر معلمان هر کلاس را نیز لود کنیم:

$students = Student::with( [ 'books', 'classes.teachers'] )->get();

foreach( $students as $student ) {

    $studentName = $student->name;

    $books = $student->books;

    $classes = $student->classes;
    Foreach($classes as $class) {
        $teachers = $class->teachers;
    }

}

در این حالت هم رابطه‌ی classes و هم رابطه‌ی teachers لود می‌شوند.

لود ستون‌های خاص

اگر بخواهیم ستون‌های خاصی را از رابطه‌ی موردنظر به دست آوریم، می‌توانیم به شکل زیر عمل کنیم:

$students = Student::with('books:id,title')->get();

foreach( $students as $student ) {

    $studentName = $student->name;

    $books = $student->books;

    Foreach($books as $book) {
        $id = $book->id;
        $title = $book->title;
    }

}

در اینجا، از رابطه‌ی books، ما فقط ستون‌های id و title را از دیتابیس گرفته‌ایم.

لود رابطه به صورت پیش‌فرض

ممکن است نیاز داشته باشید که موقع دسترسی به یک مدل، رابطه یا روابط خاصی را بدون نیاز به استفاده از متد ()with، همواره لود کنید. برای این حالت می‌توانید خصوصیت with$ را به صورت protected و با مقدار آرایه به شکل زیر تعریف کنید:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

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

    /**
     * Get all the books that the student has.
     */
    public function books()
    {
        return $this->hasMany('App\Models\Book');
    }
}

اگر برای یک کوئری خاص نیاز داشتید که رابطه‌ی موردنظرتان را از خصوصیت with$ خارج کنید تا لود نشود، می‌توانید به شکل زیر عمل کنید:

$students = App\Models\Student::without('books')->get();

ایجاد محدودیت در Eager Loading در لاراول

گاهی اوقات نیاز دارید محدودیت‌ها یا شرایطی را بر رابطه‌ای که می‌خواهید لود شود، اعمال کنید. برای این کار می‌توانید از اکثر متدهای Query Builder مانند مثال زیر استفاده کنید:

$students = App\Models\Student::with(['books' => function ($query) {
    $query->where('title', 'like', '%سیب%')->lastest('order');
}])->get();

در مثال بالا رابطه‌ی books فقط کتاب‌هایی را شامل شود که در title آن‌ها از کلمه‌ی سیب استفاده شده باشد و این کتاب‌ها برحسب ستون order و به صورت نزولی مرتب می‌شوند. دقت داشته باشید که هنگام اعمال محدودیت بر روابط از متدهای ()limit و ()take نمی‌توانید استفاده کنید.

Lazy Eager Loading در لاراول

گاهی ممکن است که فقط تحت شرایط خاصی نیاز به لود رابطه داشته باشید. برای این کار می‌توانید به شکل زیر عمل کنید:

$students = App\Models\Student::latest()->get();

if ($condition) {
    $students->load('books', 'classes');
}

اگر در این حالت نیاز داشته باشید شرایطی را بر رابطه اعمال کنید:

$students = App\Models\Student::latest()->get();

if ($condition) {
    $students->load(['books' => function ($query) {
        $query->latest();
    }, 'classes']);
}

اگر مطمئن نیستید که رابطه لود شده باشد و می‌خواهید در صورتی که لود نشده، آن را لود کنید، باید به شکل زیر عمل کنید:

$students = App\Models\Student::latest()->get();

$students->loadMissing('books');

بهینه سازی روابط در لاراول با Eager loading

جمع‌ بندی:

بعد از این که با مفهوم Eager loading در لاراول آشنا شدید، بهتر است از این امکان و ابزار فوق العاده‌ای که در فریم ورک لاراول برای شما فراهم شده، بیشتر استفاده کنید تا برنامه‌هایی کارآمد را طراحی کنید. در واقع شما تا به امروز به دلیل این که با این مفهوم آشنایی کاملی نداشتید، نمی‌توانستید از آن در برنامه‌های خود استفاده کنید به همین دلیل برنامه‌هایی که به وسیله‌ی لاراول طراحی می‌کنید دچار مشکلاتی می‌شوند که یکی از مهم‌ترین این مشکلات را می‌توان همان مشکل معروف N+1 دانست. حال که با مفهوم Eager loading در فریم ورک لاراول آشنا شدید، می‌توانید به‌راحتی این مشکل را حل کنید.

اگر به یادگیری بیشتر لاراول علاقه داری می‌توانی در دوره آموزشی لاراول کاربردی (بسته پروژه محور) شرکت کنی، این دوره شامل ۱۲ پروژه کاربردی و پر استفاده در دنیای واقعی است، که تمامی پروژه‌ها به صورت کامل برنامه‌ نویسی خواهند شد، تا دانشجو بتواند با روند ایجاد و تکمیل پروژه به صورت کامل آشنا شود.

چه امتیازی به این مقاله می دید؟
نویسنده رضا زیدی
از یادگیری ، عمل‌گرایی و چالش‌های مربوطه ، لذت می‌برم ...
ارسال دیدگاه
خوشحال میشیم دیدگاه و یا تجربیات خودتون رو با ما در میون بذارید :

 

نظرات کاربران

m3hdi

great

Morteza

در مثال آخر که کد رو نوشتید انتهای خط اول به اشتباه ()ger نوشته شده !😜