Skip to content

Day 14 — Relasi Eloquent: One-to-Many & Eager Loading

Fase: 2 — Mini Project Asset Management | Minggu: 3 | Hari: Kamis


🎯 Tujuan Hari Ini

Peserta memahami secara mendalam cara kerja Relasi Eloquent dan mengatasi masalah umum yang sering terjadi: N+1 Query Problem, kemudian mengoptimalkannya dengan Eager Loading.


📋 Task Wajib

1. Review & Verifikasi Relasi

Buka app/Models/Category.php dan app/Models/Asset.php. Pastikan relasi sudah terdefinisi dengan benar:

php
// Category.php
public function assets() {
    return $this->hasMany(Asset::class);  // 1 category → banyak assets
}

// Asset.php
public function category() {
    return $this->belongsTo(Category::class);  // 1 asset → 1 category
}

2. N+1 Query Problem: Masalah Tersembunyi

Apa itu N+1 Problem?

Perhatikan kode ini di AssetController@index:

php
// ❌ SALAH - Ini N+1 Problem!
$assets = Asset::all();  // 1 query untuk semua aset

// Lalu di view, setiap baris kita panggil:
// $asset->category->name  <-- ini menjalankan 1 query BARU per baris!

Jika ada 100 aset, maka ada 1 + 100 = 101 query! Ini sangat lambat.

Solusi: Eager Loading dengan with()

php
// ✅ BENAR - Eager Loading
$assets = Asset::with('category')->get();
// Hanya 2 query total: 1 untuk aset, 1 untuk semua kategori sekaligus

3. Implementasi Halaman Detail Category (Show)

Buat resources/views/categories/show.blade.php:

html
@extends('layouts.app')
@section('title', 'Detail Kategori')

@section('content')
<div style="margin-bottom:20px;">
    <a href="{{ route('categories.index') }}" style="color:#666; text-decoration:none;">← Kembali ke Kategori</a>
</div>

<div style="background:white; padding:30px; border-radius:10px; margin-bottom:24px; box-shadow:0 2px 8px rgba(0,0,0,0.07);">
    <h1>📂 {{ $category->name }}</h1>
    <p style="color:#666; margin-top:8px;">{{ $category->description ?? 'Tidak ada deskripsi.' }}</p>
    <div style="margin-top:16px; display:flex; gap:20px;">
        <span style="color:#999; font-size:13px;">Dibuat: {{ $category->created_at->format('d M Y') }}</span>
        <span style="background:#eef2ff; color:#4f46e5; padding:4px 12px; border-radius:20px; font-size:13px;">
            {{ $category->assets->count() }} aset terdaftar
        </span>
    </div>
</div>

<h2 style="margin-bottom:16px;">Aset dalam Kategori Ini</h2>

@if($category->assets->count() > 0)
<div style="background:white; border-radius:10px; overflow:hidden; box-shadow:0 2px 8px rgba(0,0,0,0.07);">
    <table style="width:100%; border-collapse:collapse;">
        <thead>
            <tr style="background:#f8f9fa;">
                <th style="padding:12px 16px; text-align:left;">Kode</th>
                <th style="padding:12px 16px; text-align:left;">Nama</th>
                <th style="padding:12px 16px; text-align:center;">Stock</th>
                <th style="padding:12px 16px; text-align:center;">Kondisi</th>
                <th style="padding:12px 16px; text-align:center;">Aksi</th>
            </tr>
        </thead>
        <tbody>
            @foreach($category->assets as $asset)
            <tr style="border-bottom:1px solid #f0f0f0;">
                <td style="padding:12px 16px; font-family:monospace; color:#4f46e5;">{{ $asset->code }}</td>
                <td style="padding:12px 16px;">{{ $asset->name }}</td>
                <td style="padding:12px 16px; text-align:center; font-weight:bold;">{{ $asset->stock }}</td>
                <td style="padding:12px 16px; text-align:center;">{{ ucfirst($asset->condition) }}</td>
                <td style="padding:12px 16px; text-align:center;">
                    <a href="{{ route('assets.edit', $asset->id) }}" style="color:#0066cc;">Edit</a>
                </td>
            </tr>
            @endforeach
        </tbody>
    </table>
</div>
@else
<div style="background:#fff3cd; padding:20px; border-radius:8px; color:#856404;">
    ⚠️ Kategori ini belum memiliki aset. 
    <a href="{{ route('assets.create') }}?category={{ $category->id }}">Tambahkan aset sekarang.</a>
</div>
@endif
@endsection

4. Perbaiki Semua Controller: Gunakan Eager Loading

Update semua method yang memanggil relasi:

CategoryController@index:

php
$categories = Category::withCount('assets')->orderBy('name')->get();
// withCount() = satu cara efisien mendapatkan COUNT relasi

AssetController@index:

php
$assets = Asset::with('category')->orderBy('name')->paginate(10);
// with('category') = Eager loading relasi category

5. Optimalkan Dengan Nested Eager Loading

Jika di masa depan ada halaman yang butuh data lebih dalam:

php
// Contoh: load aset beserta kategorinya DAN loan-nya sekaligus
$assets = Asset::with(['category', 'loans'])->get();

// Atau nested: load loans beserta detail asetnya
$loans = Loan::with('asset.category')->get();
// Ini membaca: "muat loans, sertakan asetnya, dan kategori dari aset tersebut"

Update link di halaman assets/index.blade.php: klik nama kategori agar menuju halaman detail kategori.

html
<td style="padding:14px 16px;">
    <a href="{{ route('categories.show', $asset->category_id) }}" 
       style="color:#4f46e5; text-decoration:none;">
        {{ $asset->category->name }}
    </a>
</td>

📝 Laporan ke Mentor

📌 LAPORAN HARIAN — Day 14
Nama     : [Nama Lengkap]
Role     : [Role Kamu]

✅ Yang saya kerjakan hari ini:
- [ ] Memahami dan bisa menjelaskan N+1 Problem
- [ ] Semua controller sudah menggunakan eager loading with()
- [ ] Halaman categories/show.blade.php selesai dan tampil daftar aset
- [ ] Link kategori di halaman aset menuju ke detail kategori

📸 Screenshot Wajib:
1. Halaman /categories/{id} menampilkan daftar aset dalam kategori
2. Tabel aset di /assets — kolom kategori adalah link yang bisa diklik

🧠 Pertanyaan Pemahaman (jawab di laporan):
Q: Apa perbedaan output antara kode ini:
   (A) Asset::all()
   (B) Asset::with('category')->get()
A: [Jawaban kamu]

❓ Kendala:
[Tulis jika ada]

Catatan Mentor

Jika tersedia Laravel Debugbar (composer require barryvdh/laravel-debugbar --dev), install dan tunjukkan secara langsung berapa banyak query yang dijalankan dengan dan tanpa eager loading. Ini akan sangat berkesan bagi peserta dan membuat mereka memahami pentingnya optimasi.

Program Magang SMK RPL — Rekayasa Perangkat Lunak