وقتی پروژه لاراولی از حالت ساده بیرون می آید، کوئری ها هم دیگر فقط یک where و orderBy نیستند. گزارش گیری، فیلترهای چندگانه، ارتباط چند جدول، شرط های پویا و بهینه سازی عملکرد وارد ماجرا می شوند. اینجا دقیقا جایی است که eloquent در لاراول اگر درست استفاده شود، هم کد را تمیز نگه می دارد و هم کوئری های پیچیده را قابل کنترل می کند. اگر هم بد استفاده شود، به راحتی می تواند باعث N+1، کندی شدید و کد شلوغ شود.

چرا Eloquent برای کوئری های پیچیده هنوز انتخاب خوبی است

Eloquent فقط یک ابزار ساده برای CRUD نیست. وقتی ساختار مدل ها درست طراحی شود، می توانی اکثر نیازهای واقعی را با query builder داخلی آن انجام بدهی. مزیت اصلی این است که منطق دیتابیس به شکل قابل خواندن داخل کد می نشیند. همچنین با scope ها، relation ها و eager loading می توانی پیچیدگی را مدیریت کنی بدون اینکه کد تبدیل به یک جنگل از SQL خام شود.

ساختن فیلترهای پویا با when

یکی از بهترین تکنیک ها برای کوئری های پیچیده، استفاده از when است. چون در پروژه واقعی فیلترها معمولا اختیاری هستند. مثلا کاربر ممکن است فقط تاریخ بدهد یا فقط وضعیت سفارش. when کمک می کند شرط ها تمیز و مرحله ای اضافه شوند.
به جای چندین if پشت سر هم، یک زنجیره قابل خواندن داری که به راحتی نگهداری می شود.

گروه بندی شرط ها با where و closure

وقتی شرط های ترکیبی داری، مخصوصا AND و OR، باید حواست به پرانتزهای منطقی باشد. در Eloquent این کار با closure داخل where انجام می شود. این روش باعث می شود نتیجه کوئری دقیقا همان چیزی باشد که انتظار داری و به خاطر اولویت عملگرها اشتباه نشود.

کار با relationship ها برای کوئری های چند جدولی

یکی از قدرت های eloquent در لاراول این است که به جای join های طولانی، از relation ها استفاده می کنی. مثلا برای فیلتر کردن سفارش هایی که کاربر خاصی دارند یا محصول خاصی داخل آنهاست، می توانی از whereHas استفاده کنی. این روش هم خواناست و هم از نظر منطقی نزدیک به دامنه کسب و کار است.

whereHas و has برای فیلتر بر اساس رابطه

whereHas زمانی استفاده می شود که هم رابطه وجود داشته باشد و هم شرط داخل آن رابطه مهم باشد. مثلا کاربرانی که حداقل یک سفارش با وضعیت پرداخت شده دارند. این الگو در گزارش گیری و داشبوردها بسیار رایج است و اگر درست استفاده شود، کد را خیلی تمیز می کند.

eager loading برای جلوگیری از مشکل N+1

یکی از بدترین خطاها در کوئری های پیچیده N+1 است. یعنی یک لیست را می گیری و بعد برای هر آیتم جداگانه یک کوئری می زند. در پروژه واقعی این مشکل می تواند دیتابیس را نابود کند. راه درست استفاده از with و eager loading است. یعنی از ابتدا رابطه ها را با همان کوئری اصلی بارگذاری کنی.

محدود کردن داده های رابطه با select و with

گاهی لازم نیست تمام ستون های جدول مرتبط را بگیری. می توانی داخل with مشخص کنی فقط فیلدهای لازم لود شوند. این کار حجم داده را کم می کند و پاسخ API یا صفحه را سبک تر می کند. برای پروژه های پرترافیک، این نکته خیلی مهم است.

ساخت کوئری های گزارش گیری با aggregate ها

کوئری های پیچیده معمولا گزارش گیری هستند. count، sum، avg و groupBy زیاد استفاده می شوند. Eloquent و query builder این امکانات را دارند. نکته مهم این است که برای گزارش های سنگین، بهتر است aggregate ها را مستقیم در دیتابیس انجام بدهی و داده خام را به PHP نکشی.

Subquery و استفاده از selectSub

بعضی وقت ها لازم است داخل یک کوئری، یک کوئری دیگر داشته باشی. مثلا آخرین تاریخ سفارش هر کاربر یا مجموع پرداختی ها. در لاراول می توانی از selectSub و joinSub استفاده کنی. این روش در پروژه های واقعی خیلی کاربرد دارد و جلوی چند بار query زدن را می گیرد.

join در Eloquent و اینکه چه زمانی لازم می شود

اگر هدف فقط فیلتر کردن یا گرفتن یک ستون از جدول دیگر است، relation ها کافی هستند. اما گاهی join بهتر و سریع تر است، مخصوصا برای گزارش ها و مرتب سازی بر اساس ستون جدول دیگر. اینجا باید تصمیم بگیری readability مهم تر است یا performance. برای گزارش های سنگین معمولا join انتخاب منطقی تری است.

paginate برای خروجی های بزرگ

کوئری پیچیده معمولا خروجی زیاد دارد. گرفتن همه داده ها یکجا نه درست است و نه بهینه. paginate و simplePaginate کمک می کنند خروجی مرحله ای باشد. این کار هم فشار دیتابیس را کم می کند و هم تجربه کاربر را بهتر می کند.

Scope ها برای تمیز نگه داشتن کوئری

وقتی یک فیلتر یا شرط در چند جای پروژه تکرار می شود، باید آن را تبدیل به scope کنی. مثلا scopeActive یا scopePaid. این کار باعث می شود کوئری ها کوتاه تر و قابل فهم تر شوند. در پروژه های واقعی، scope ها یکی از بهترین راه ها برای مدیریت eloquent در لاراول هستند.

استفاده از accessor و cast برای داده های خاص

بعضی وقت ها پیچیدگی فقط در کوئری نیست، در شکل داده هم هست. مثلا تاریخ ها، JSON یا پول. با cast ها و accessor ها می توانی خروجی را استاندارد کنی بدون اینکه در همه جا تبدیل انجام دهی. این کار باعث می شود کد بخش های دیگر ساده تر شود.

بهینه سازی عملکرد با index و بررسی query ها

هیچ کوئری پیچیده ای بدون توجه به ایندکس ها سریع نمی شود. اگر روی ستون هایی که زیاد فیلتر می شوند index نگذاری، هرچقدر هم eloquent تمیز باشد، سرعت پایین می آید. همچنین باید query log را بررسی کنی و ببینی دقیقا چه SQL تولید می شود. این قسمت از کار، توسعه دهنده حرفه ای را از متوسط جدا می کند.

اشتباهات رایج در کوئری های پیچیده با Eloquent

یکی از اشتباهات رایج این است که با Eloquent همه چیز را مثل یک لیست ساده fetch کنند و بعد در PHP فیلتر و مرتب سازی انجام دهند. این کار هم کند است و هم حافظه را می ترکاند. اشتباه دیگر استفاده نکردن از eager loading و ایجاد N+1 است. اشتباه سوم این است که scope ها را جدی نگیرند و کوئری ها در همه جا تکرار شود.

چه زمانی SQL خام بهتر است

گاهی واقعا نیاز به SQL خام داری. مثلا گزارش های بسیار سنگین، window function ها یا کوئری های خاص. در این حالت استفاده از DB::raw یا query builder منطقی است. اما حتی اینجا هم بهتر است تا جای ممکن ساختار را قابل فهم نگه داری. هدف این نیست که Eloquent را کنار بگذاری، هدف این است که ابزار درست را در جای درست استفاده کنی.

جمع بندی

eloquent در لاراول اگر با تکنیک های درست استفاده شود، برای کوئری های پیچیده هم کاملا جواب می دهد. when برای شرط های پویا، whereHas برای فیلترهای رابطه ای، eager loading برای جلوگیری از N+1، scope برای تمیزکاری کد و join یا subquery برای گزارش های سنگین، ابزارهای اصلی تو هستند. اگر این اصول را رعایت کنی، هم کد خوانا می ماند و هم دیتابیس زیر فشار نمی شکند.