Как удалить несколько записей с помощью 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(...) {
    }
}

таким образом, вы найдете все продукты с заданными идентификаторами и удалить их все.