ฉันได้พบแนวคิดและความหมายเบื้องหลังวิธีการเหล่านี้ทำให้เกิดความสับสนเล็กน้อยเป็นไปได้หรือไม่ที่บางคนจะอธิบายให้ฉันฟังว่าความแตกต่างระหว่างhas
และwith
เป็นอย่างไรในบริบทของตัวอย่าง (ถ้าเป็นไปได้)
ฉันได้พบแนวคิดและความหมายเบื้องหลังวิธีการเหล่านี้ทำให้เกิดความสับสนเล็กน้อยเป็นไปได้หรือไม่ที่บางคนจะอธิบายให้ฉันฟังว่าความแตกต่างระหว่างhas
และwith
เป็นอย่างไรในบริบทของตัวอย่าง (ถ้าเป็นไปได้)
คำตอบ:
with()
สำหรับการโหลดที่กระตือรือร้นการโหลดกระตือรือร้นนั่นหมายความว่าโดยพื้นฐานแล้ว Laravel จะโหลดความสัมพันธ์ที่คุณระบุล่วงหน้า สิ่งนี้มีประโยชน์อย่างยิ่งหากคุณมีโมเดลหลายรุ่นและคุณต้องการโหลดความสัมพันธ์สำหรับพวกเขาทั้งหมด เพราะด้วยความกระตือรือร้นในการโหลดคุณจึงเรียกใช้แบบสอบถามฐานข้อมูลเพิ่มเติมเพียงหนึ่งแบบสอบถามแทนที่จะเป็นหนึ่งแบบสอบถามสำหรับทุกรุ่นในคอลเลกชัน
ตัวอย่าง:
User > hasMany > Post
$users = User::with('posts')->get();
foreach($users as $user){
$users->posts; // posts is already loaded and no additional DB query is run
}
has()
คือการกรองรูปแบบการเลือกตามความสัมพันธ์ ดังนั้นมันจึงทำหน้าที่คล้ายกันมากกับสภาพ WHERE ปกติ ถ้าคุณใช้has('relation')
นั่นหมายความว่าคุณต้องการรับโมเดลที่มีโมเดลที่เกี่ยวข้องอย่างน้อยหนึ่งรุ่นในความสัมพันธ์นี้
ตัวอย่าง:
User > hasMany > Post
$users = User::has('posts')->get();
// only users that have at least one post are contained in the collection
whereHas()
ทำงานโดยทั่วไปเหมือนกับhas()
แต่อนุญาตให้คุณระบุตัวกรองเพิ่มเติมสำหรับรุ่นที่เกี่ยวข้องเพื่อตรวจสอบ
ตัวอย่าง:
User > hasMany > Post
$users = User::whereHas('posts', function($q){
$q->where('created_at', '>=', '2015-01-01 00:00:00');
})->get();
// only users that have posts from 2015 on forward are returned
whereHas
กับความสัมพันธ์ของผู้ใช้เมื่อทำการสอบถามโพสต์
whereHas
มันจะใช้use Illuminate\Database\Eloquent\Builder;
กับสิ่งfunction(Builder $query)
นั้น ตัวอย่างส่วนใหญ่ที่ฉันเห็นจุดใช้Builder
เพียงแค่ผ่านในแบบสอบถาม $ ซึ่งเป็นวิธีที่ถูกต้องหรือไม่
เอกสารอธิบายการใช้งานแล้ว ดังนั้นฉันใช้ SQL เพื่ออธิบายวิธีการเหล่านี้
สมมติว่ามีOrder (orders)
หลายOrderItem (order_items)
อย่าง
และคุณได้สร้างความสัมพันธ์ระหว่างพวกเขาแล้ว
// App\Models\Order:
public function orderItems() {
return $this->hasMany('App\Models\OrderItem', 'order_id', 'id');
}
ทั้งสามวิธีการทั้งหมดขึ้นอยู่กับความสัมพันธ์
ผลลัพธ์: with()
ส่งคืนโมเดลวัตถุและผลลัพธ์ที่เกี่ยวข้อง
ประโยชน์:มันเป็นความกระตือรือร้นในการโหลดที่สามารถป้องกันไม่ให้ปัญหา N + 1
เมื่อคุณใช้ Eloquent Builder ต่อไปนี้:
Order::with('orderItems')->get();
Laravel เปลี่ยนรหัสนี้เป็นสอง SQL เท่านั้น :
// get all orders:
SELECT * FROM orders;
// get the order_items based on the orders' id above
SELECT * FROM order_items WHERE order_items.order_id IN (1,2,3,4...);
จากนั้น laravel จะรวมผลลัพธ์ของ SQL ที่สองซึ่งแตกต่างจากผลลัพธ์ของ SQL แรกด้วยforeign keyต่างประเทศที่สำคัญในที่สุดก็กลับมาผลการเก็บรวบรวม
ดังนั้นหากคุณเลือกคอลัมน์ที่ไม่มีการปิด foreign_key ผลลัพธ์ความสัมพันธ์จะว่างเปล่า:
Order::with(['orderItems' => function($query) {
// $query->sum('quantity');
$query->select('quantity'); // without `order_id`
}
])->get();
#=> result:
[{ id: 1,
code: '00001',
orderItems: [], // <== is empty
},{
id: 2,
code: '00002',
orderItems: [], // <== is empty
}...
}]
Has
จะกลับวัตถุแบบจำลองที่ความสัมพันธ์ของตนไม่ว่างเปล่า
Order::has('orderItems')->get();
Laravel เปลี่ยนรหัสนี้เป็นหนึ่ง SQL :
select * from `orders` where exists (
select * from `order_items` where `order`.`id` = `order_item`.`order_id`
)
whereHas
และorWhereHas
วิธีการที่จะวางwhere
เงื่อนไขในhas
แบบสอบถามของคุณ วิธีการเหล่านี้ช่วยให้คุณสามารถเพิ่มข้อ จำกัด การปรับแต่งเพื่อ จำกัด
Order::whereHas('orderItems', function($query) {
$query->where('status', 1);
})->get();
Laravel เปลี่ยนรหัสนี้เป็นหนึ่ง SQL :
select * from `orders` where exists (
select *
from `order_items`
where `orders`.`id` = `order_items`.`order_id` and `status` = 1
)
with('relation')
จะรวมข้อมูลของตารางที่เกี่ยวข้องในการรวบรวมที่ส่งคืนhas('relation')
และwhereHas('relation')
จะไม่รวมข้อมูลของตารางที่เกี่ยวข้อง ดังนั้นคุณอาจจะต้องเรียกทั้งสองwith('relation')
เช่นเดียวกับหรือhas()
whereHas()