Как удалить несколько записей с помощью Laravel Eloquent
я хочу иметь возможность удалять несколько записей из базы данных. У меня есть id
из всех записей, которые я хочу удалить. Я вызываю resource.destroy
маршрут с использованием списка идентификаторов, разделенных запятыми (id
имеет тип postgres uuid
), вот так:
Request URL:http://foo.app/products/62100dd6-7ecf-4870-aa79-4b132e60c904,c4b369f1-d1ef-4aa2-b4df-b9bc300a4ff5
Request Method:DELETE
на другом конце мое действие контроллера выглядит так:
public function destroy($id)
{
try {
$ids = explode(",", $id);
$org->products()->find($ids)->delete();
}
catch(...) {
}
}
это дает мне следующую ошибка:
BadMethodCallException in Macroable.php line 81:
Method delete does not exist.
in Macroable.php line 81
at Collection->__call('delete', array()) in ProductsController.php line 251
at Collection->delete() in ProductsController.php line 251
at ProductsController->destroy('62100dd6-7ecf-4870-aa79-4b132e60c904,c4b369f1-d1ef-4aa2-b4df-b9bc300a4ff5')
я это проверил find()
возвращает коллекцию products
соответствие указанным идентификаторам.
что я упустил?
PS:
1. Модель Product
несколько belongsTo
отношения с другими моделями.
2. The product.destroy
код отлично работает, если я передаю его один id
редактировать Я думаю, я также пытаюсь понять, в чем разница между:
$org->products()->find($ids)->delete()
и
$org->products()->whereIn('id', $ids)->get()->delete()
- это? Из того, что я вижу, оба!--15--> и get
возвращается Collections
3 ответов
проблема в том, что ты называешь delete()
В коллекции, которая не имеет этого метода.
у вас есть несколько вариантов здесь.
Модель Событий
если у вас есть прослушиватели событий для deleting
/deleted
события модели, вам нужно будет убедиться, что удаление происходит таким образом, что каждая модель загружается, а затем удаляется.
в этом случае, вы можете использовать destroy
метод на модели, которая принимает список идентификаторов. Он загрузит новую модель для каждого ID, а затем вызвать delete()
на нем. Как вы упоминаете в комментарии, он не будет ограничивать удаление только теми продуктами в организации, поэтому вам нужно будет отфильтровать эти идентификаторы перед передачей списка в destroy()
метод.
public function destroy($id)
{
try {
$ids = explode(",", $id);
// intersect the product ids for the org with those passed in
$orgIds = array_intersect($org->products()->lists('id'), $ids);
// now this will only destroy ids associated with the org
\App\Product::destroy($orgIds);
}
catch(...) {
}
}
Если вам не особенно нравится этот подход, вам нужно будет повторить свою коллекцию продуктов организации и позвонить delete()
на них в отдельности. Вы можете использовать стандарт foreach
, или вы можете использовать each
метод сбора:
public function destroy($id)
{
try {
$ids = explode(",", $id);
$org->products()->find($ids)->each(function ($product, $key) {
$product->delete();
});
}
catch(...) {
}
}
Нет Модельных Событий
теперь, если у вас нет каких-либо модельных событий, которые вам нужно слушать, все немного проще. В этом случае, вы можете просто позвонить delete()
в построителе запросов, и он будет идти прямо до удаления записей без загрузки каких-либо объектов модели. Таким образом, вы получаете более чистый код с лучшей производительностью:
public function destroy($id)
{
try {
$ids = explode(",", $id);
// call delete on the query builder (no get())
$org->products()->whereIn('id', $ids)->delete();
}
catch(...) {
}
}
Я также столкнулся с этой проблемой. Пусть $orgs
содержит некоторые записи в виде коллекции. Теперь вы можете легко удалить эти записи, используя такой цикл-
foreach($orgs as $org)
{
$org->delete();
}
когда вы используете метод find, он найдет только один идентификатор. Вы должны использовать where, чтобы соответствовать нескольким идентификаторам
public function destroy($id)
{
try {
$ids = explode(",", $id);
$org->products()->whereIn('id', $ids)->get()->delete();
}
catch(...) {
}
}
таким образом, вы найдете все продукты с заданными идентификаторами и удалить их все.