Laravel - เก่ง“ มี”,“ พร้อม”,“ ที่ไหนมี” - พวกเขาหมายถึงอะไร?


212

ฉันได้พบแนวคิดและความหมายเบื้องหลังวิธีการเหล่านี้ทำให้เกิดความสับสนเล็กน้อยเป็นไปได้หรือไม่ที่บางคนจะอธิบายให้ฉันฟังว่าความแตกต่างระหว่างhasและwithเป็นอย่างไรในบริบทของตัวอย่าง (ถ้าเป็นไปได้)

คำตอบ:


556

กับ

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

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

101
+1 คำตอบที่เป็นประโยชน์มาก! โปรดทราบว่าในขณะที่with('relation')จะรวมข้อมูลของตารางที่เกี่ยวข้องในการรวบรวมที่ส่งคืนhas('relation')และwhereHas('relation')จะไม่รวมข้อมูลของตารางที่เกี่ยวข้อง ดังนั้นคุณอาจจะต้องเรียกทั้งสองwith('relation')เช่นเดียวกับหรือhas() whereHas()
Soulriser

1
ทักทายคำตอบวิธีการเข้าถึงโมเดลผู้ปกครองจากโมเดลความสัมพันธ์เช่นที่นี่วิธีค้นหาโมเดลโพสต์ตามคุณลักษณะของโมเดลผู้ใช้
hussainfrotan

@ BhojendraNepal โชคไม่ดีที่มีเอกสารเกี่ยวกับมันเยอะมาก ... นี่คือทั้งหมดที่ฉันพบ (มันมีอยู่สองสามย่อหน้า)
lukasgeiter

@hussainfrotan ในลักษณะเดียวกันใช้whereHasกับความสัมพันธ์ของผู้ใช้เมื่อทำการสอบถามโพสต์
Michael Tsang

อยากรู้อยากเห็นในเอกสาร Laravel: laravel.com/docs/5.8/eloquent- relationshipsเมื่อใช้whereHasมันจะใช้use Illuminate\Database\Eloquent\Builder;กับสิ่งfunction(Builder $query)นั้น ตัวอย่างส่วนใหญ่ที่ฉันเห็นจุดใช้Builderเพียงแค่ผ่านในแบบสอบถาม $ ซึ่งเป็นวิธีที่ถูกต้องหรือไม่
Guntar

8

เอกสารอธิบายการใช้งานแล้ว ดังนั้นฉันใช้ 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


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
)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.