简体   繁体   English

如何使用 Laravel Eloquent 删除多条记录

[英]How to delete multiple records using Laravel Eloquent

Now this, from what I can see, should have been simple.现在,从我所见,这应该很简单。

I want to be able to delete multiple records from the database.我希望能够从数据库中删除多条记录。 I have the id 's of all the records I wish to delete.我有我想删除的所有记录的id I call the resource.destroy route using comma separated list of ids ( id is of postgres type uuid ), like so:我使用逗号分隔的 id 列表( id是 postgres 类型uuid )调用resource.destroy路由,如下所示:

Request URL:http://foo.app/products/62100dd6-7ecf-4870-aa79-4b132e60c904,c4b369f1-d1ef-4aa2-b4df-b9bc300a4ff5
Request Method:DELETE

On the other end, my controller action looks like so:另一方面,我的控制器操作如下所示:

public function destroy($id)
{
    try {
        $ids = explode(",", $id);
        $org->products()->find($ids)->delete();
    }
    catch(...) {
    }
}

This gives me the following error:这给了我以下错误:

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')

I have verified that find() is returning a collection of products matching the specified ids.我已经验证find()正在返回与指定 ID 匹配的products集合。

What am I missing?我错过了什么?

PS: 1. The model Product has several belongsTo relationships with other models. PS:1.模型Product与其他模型有几个belongsTo关系。 2. The product.destroy code works fine if I pass it a single id 2. product.destroy代码工作正常,如果我给它传递一个id

EDIT I guess, I'm also trying to understand what the difference between:编辑我想,我也想了解两者之间的区别:

$org->products()->find($ids)->delete()

and

$org->products()->whereIn('id', $ids)->get()->delete()

is?是? From what I see, both find and get are returning Collections从我所见, findget都在返回Collections

The issue is that you're calling delete() on a Collection, which does not have that method.问题是您在没有该方法的集合上调用delete()

You have a couple options here.你有几个选择。

Model Events模型事件

If you have event listeners for the deleting / deleted model events, you will need to make sure the deletion happens in a way that each model is loaded and then deleted.如果您有deleting / deleted模型事件的事件侦听器,您将需要确保以每个模型加载然后删除的方式进行删除。

In this case, you can use the destroy method on the model that takes a list of ids.在这种情况下,您可以在采用 id 列表的模型上使用destroy方法。 It will load a new model for each id, and then call delete() on it.它将为每个 id 加载一个新模型,然后对其调用delete() As you mention in a comment, it won't restrict the deletion to only those products in the organization, so you would need to filter out those ids before passing the list into the destroy() method.正如您在评论中提到的,它不会将删除仅限于组织中的那些产品,因此您需要在将列表传递到destroy()方法之前过滤掉这些 id。

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(...) {
    }
}

If you don't particularly like that approach, you will need to iterate your collection of organization products and call delete() on them individually.如果您不是特别喜欢这种方法,您将需要迭代您的组织产品集合并分别对它们调用delete() You can use a standard foreach , or you can use the each method on the collection:您可以使用标准foreach ,也可以使用集合上的each方法:

public function destroy($id)
{
    try {
        $ids = explode(",", $id);
        $org->products()->find($ids)->each(function ($product, $key) {
            $product->delete();
        });
    }
    catch(...) {
    }
}

No Model Events没有模型事件

Now, if you don't have any model events that you need to listen for, things are a little easier.现在,如果您没有任何需要监听的模型事件,事情就会变得简单一些。 In this case, you can just call delete() on the query builder, and it will go straight to deleting the records without loading any model objects.在这种情况下,您只需在查询构建器上调用delete() ,它将直接删除记录而不加载任何模型对象。 So, you get cleaner code with better performance:因此,您可以获得更清晰的代码和更好的性能:

public function destroy($id)
{
    try {
        $ids = explode(",", $id);
        // call delete on the query builder (no get())
        $org->products()->whereIn('id', $ids)->delete();
    }
    catch(...) {
    }
}

If you create a model of your products, it will help you with these types of operations.如果您创建产品模型,它将帮助您完成这些类型的操作。

For example:例如:

the model Products.php模型Products.php

<?php

namespace App\Http\Models;

use Illuminate\Database\Eloquent\Model;

class Products extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'products';
    protected $primaryKey = 'id';

    protected $fillable = ['name', 'price', 'description'];


}

The controller Products.php控制器Products.php

You can use the destroy method and pass one or more primary keys to it as arguments.您可以使用destroy方法并将一个或多个主键作为参数传递给它。

<?php

    namespace App\Http\Controllers;

    use App\Http\Models\Products;

    class Products 
    {
        
        public function destroy($id)
        {
            try {
                
                $ids = explode(",", $id);
                //$ids is a Array with the primary keys
                Products::destroy($ids);
            }
            catch(...) {
            }
        }

    }

You can also use this option to remove query results with a custom parameter您还可以使用此选项删除带有自定义参数的查询结果

$deletedRows = Products::where('name', 'phones')->delete();

You can check the Laravel documentation https://laravel.com/docs/8.x/eloquent#soft-deleting您可以查看 Laravel 文档https://laravel.com/docs/8.x/eloquent#soft-deleting

When you use the find method, it will find only a single ID.当您使用 find 方法时,它只会找到一个 ID。 You should use a whereIn to match multiple ids您应该使用 whereIn 来匹配多个 id

public function destroy($id)
{
    try {
        $ids = explode(",", $id);
        $org->products()->whereIn('id', $ids)->get()->delete(); 
    }
    catch(...) {
    }
}

This way you will find all the products with the given IDs and delete them all.这样,您将找到具有给定 ID 的所有产品并将其全部删除。

I also faced this problem.我也遇到了这个问题。 Let $orgs contains some records as a collection.$orgs包含一些记录作为集合。 Now you can easily delete these records using a loop like this-现在您可以使用这样的循环轻松删除这些记录-

foreach($orgs as $org) 
{
    $org->delete();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM