Laravel - красноречивые слова «имеет», «с», «где» - что они имеют в виду?

212

Я нашел концепцию и значение этих методов немного запутанными, возможно ли, чтобы кто-то объяснил мне, в чем разница между hasи withв контексте примера (если это возможно)?

lukasgeiter
источник

Ответы:

558

С участием

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()является фильтрация модели выбора на основе отношений. Так что он действует очень похоже на нормальное состояние ГДЕ. Если вы просто используете это, 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
lukasgeiter
источник
101
+1, очень полезный ответ! Также обратите внимание, что while with('relation')будет включать данные связанной таблицы в возвращенную коллекцию has('relation')и неwhereHas('relation') будет включать данные связанной таблицы. Таким образом, вам может понадобиться позвонить как, так и или . with('relation')has()whereHas()
Soulriser
1
Привет Ответ, Как получить доступ к родительской модели из модели отношений, например, здесь, как искать модель поста на основе атрибутов пользовательской модели
hussainfrotan
@BhojendraNepal К сожалению, в документах об этом ничего не говорится ... Это все, что я нашел (это несколько абзацев ниже)
lukasgeiter
@hussainfrotan так же, используйте whereHasотношение пользователя при запросе поста.
Майкл Цанг
Любопытно, в документации Laravel: laravel.com/docs/5.8/eloquent-relationships , при использовании whereHasон использует use Illuminate\Database\Eloquent\Builder;то, что с function(Builder $query). Большинство примеров, которые я видел, используют точку Builder, просто передают запрос $, что является правильным способом?
Гунтар
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 в закрытии, результат отношения будет пустым:

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
)
TsaiKoga
источник