ยกตัวอย่างการเข้าถึง Post Model ผ่าน User Model
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { /** * Get all of the posts for the user. */ public function posts() { return $this->hasMany('App\Post'); } } |
สามารถเข้าถึงและฟิวด์เตอร์ข้อมูลต่างๆได้
1 2 3 |
$user = App\User::find(1); $user->posts()->where('active', 1)->get(); |
สามารถใช้ query builder ใน Eloquent: Relationships ได้
ตัวอย่างเช่น สมมติว่าคุณต้องการเรียกใช้บทความบล็อกทั้งหมดที่มีความคิดเห็นอย่างน้อยหนึ่งความคิดเห็น เป็นต้น
1 2 |
// Retrieve all posts that have at least one comment... $posts = App\Post::has('comments')->get(); |
สามารถใช้ operator ได้
1 2 |
// Retrieve all posts that have three or more comments... $posts = Post::has('comments', '>=', 3)->get(); |
ต้องการบทความทั้งหมดที่มีความคิดเห็นอย่างน้อยหนึ่งความคิดเห็นและมีโหวตด้วย
1 2 |
// Retrieve all posts that have at least one comment with votes... $posts = Post::has('comments.votes')->get(); |
นอกจากนี้หากต้องการฟิวเตอร์ข้อมูลมากกว่านั้นยังสามารถใช้ whereHas และ orWhereHas ตัวอย่างข้างล่างคือ ต้องการบทความทั้งหมดที่ใน content ของ comment ขึ้นต้นด้วย foo
1 2 3 4 |
// Retrieve all posts with at least one comment containing words like foo% $posts = Post::whereHas('comments', function ($query) { $query->where('content', 'like', 'foo%'); })->get(); |
ต้องการบทความทั้งหมดที่ไม่มีความคิดเห็น
1 |
$posts = App\Post::doesntHave('comments')->get(); |
ต้องการบทความทั้งหมดที่ในความคิดเห็นฟิวด์ content ไม่ได้ขึ้นต้นด้วย foo
1 2 3 |
$posts = Post::whereDoesntHave('comments', function ($query) { $query->where('content', 'like', 'foo%'); })->get(); |
นับจำนวนผลการค้นหาจากความสัมพันธ์โดยไม่ต้องโหลดข้อมูลจริง ให้ใช้ withCount
และใช้ฟิวด์ชื่อ {relation}_count
เป็น Column ในการแสดงผลข้อมูล
1 2 3 4 5 |
$posts = App\Post::withCount('comments')->get(); foreach ($posts as $post) { echo $post->comments_count; } |
นับผลการค้นหาจากหลายๆความสัมพันธ์
1 2 3 4 5 6 |
$posts = Post::withCount(['votes', 'comments' => function ($query) { $query->where('content', 'like', 'foo%'); }])->get(); echo $posts[0]->votes_count; echo $posts[0]->comments_count; |
นับผลการค้นหาได้หลายครั้งจากความสัมพันธ์เดียว
1 2 3 4 5 6 7 8 9 10 |
$posts = Post::withCount([ 'comments', 'comments AS pending_comments' => function ($query) { $query->where('approved', false); } ])->get(); echo $posts[0]->comments_count; echo $posts[0]->pending_comments_count; |
คือการจัดการๆปัญหาการคิวรี้แบบลูกโซ่ ตัวอย่างข้างล่าง หนังสือมีผู้แต่งได้หลายคน
Book Model
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Book extends Model { /** * Get the author that wrote the book. */ public function author() { return $this->belongsTo('App\Author'); } } |
ทำการดึงข้อมูลชื่อผู้แต่ง
1 2 3 4 5 |
$books = App\Book::all(); foreach ($books as $book) { echo $book->author->name; } |
เมื่อทำการคิวรี่ก็จะมีการคิวรี่เกิดขึ้นหลายครั้งเพราะหนังสือแต่ละเล่มก็จะไปค้นหา ผู้แต่งของมันด้วย ซึ่งจะทำให้ช้ามาก แต่ Laravel ก็เตรียมฟังก์ชัน with ไว้ให้แล้วครับ
1 2 3 4 5 |
$books = App\Book::with('author')->get(); foreach ($books as $book) { echo $book->author->name; } |
ถ้าเราใช้ฟังก์ชัน with จะมีการคิวรี่แค่สองครั้งตามข้างล่างนี้เลยครับ
1 2 3 |
select * from books select * from authors where id in (1, 2, 3, 4, 5, ...) |
ใช้กับหลายๆความสัมพันธ์
1 |
$books = App\Book::with(['author', 'publisher'])->get(); |
นอกจากนี้ยังสามารถใช้ query builder เพื่อโหลดเฉพาะ posts ที่ต้องการได้
1 2 3 |
$users = App\User::with(['posts' => function ($query) { $query->where('title', 'like', '%first%'); }])->get(); |
1 2 3 |
$users = App\User::with(['posts' => function ($query) { $query->orderBy('created_at', 'desc'); }])->get(); |
ตัวอย่างการใช้ ไปสอบถามในกลุ่ม Laravel Thailand มา มีพี่ๆใจดีมาตอบครับ
คำถาม
สอบถามเรื่อง Eager loading ครับ เพื่อความแน่ใจ
คือผมมีตาราง Car กับตาราง User
ซึ่ง User 1 คนสามารถสร้าง Car ได้หลาย Car
และ Car สามารถมี User ได้แค่ 1 คนใน CarController ผมต้องใช้ with ไหมครับ
$results = Car::with(‘user’)หรือจะใช้ก็ต่อเมื่ออยู่ใน UserController
$results = User::with(‘car’)แล้ว Eager loading นี้ใช้ในกรณีไหนบ้างครับ ตอนนี้ผมเข้าใจว่าใช้ทุกกรณีที่ Model มี Relation ผมเข้าใจถูกไหม
คำตอบ
กรณีที่ 1 ในหน้า show user 1 คน
เราต้องการให้หน้าที่แสดง user และ cars ทั้งหมดของ users นั้น อันนี้ไม่จำเป็นต้อง eager load ครับ เพราะลงท้ายแล้วจะมี 2 query อยู่ดีคือ เรียก user กับเอา user_id ไปหา carsกรณีที่ 2 ในหน้า list user ทั้งหมด (อาจจะ 10 คน หรืออะไรก็ว่าไป)
โดยในหน้านี้ สมมุติว่าเราต้องการให้มันแสดง cars ทั้งหมดด้วย code ประมาณ
@foreach($users as $user)
{{ $user->name }}
<ul>
@foreach($user->cars as $car)
<li>{{$car->model }}</li>
@endforeach
</ul>
@endforeach
ในกรณี จะเห็นว่า ใน loop มีการเรียกใช้ $user->cars ซึ่งถ้าผ่านบรรทัดนี้ 1 ครั้งมันจะ query หา cars ทั้งหมดของ user นั้น 1 ที
ถ้าสมมุติหน้านั้นแสดง 10 user จะใช้ทั้งหมด 1(เรียก user) + 10 (เรียก cars ของแต่ละ user)
ในกรณีนี้สมควรใช้ eager load เพื่อลด query โดยอาจจะใช้ ->load หรือ ->with ก็ได้ แล้วแต่่าใช้กับ collection หรือ query builderกรณีที่ 3 ในหน้า show user 1 คน
เราต้องการให้หน้าที่แสดง user และ cars ทั้งหมดของ users นั้น เหมือนอันแรก แต่บังเอิญว่า รถแต่ละคัน มันดันมีความสัมพันธ์กับตารางประกันประกัน และเราต้องการแสดงประกันด้วย ประมาณนี้
{{ $user->name }}
<ul>
@foreach($user->cars as $car)
<li>{{$car->model }} {{ $car->insurane->name }}</li>
@endforeach
</ul>
อันนี้จำคล้ายกรณีที่ 2 คือมันผ่าน $car->insurane หลายรอบ แต่ละรอบคือ 1 query ดังนั้นอันนี้ก็ควรต้อง eager load เช้นกัน
ที่มา
https://laravel.com/docs/5.4/eloquent-relationships#querying-relations
http://www.thaicreate.com/community/laravel-eloquent-orm-model-part.html
http://www.qsbg.org/BGOaudit/file/1.pdf
ป้ายกำกับ:laravel