php 自动删除 Laravel 中的相关行(Eloquent ORM)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14174070/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 06:48:01  来源:igfitidea点击:

Automatically deleting related rows in Laravel (Eloquent ORM)

phplaravel

提问by Martti Laine

When I delete a row using this syntax:

当我使用以下语法删除一行时:

$user->delete();

Is there a way to attach a callback of sorts, so that it would e.g. do this automatically:

有没有办法附加各种回调,以便它可以自动执行此操作:

$this->photo()->delete();

Preferably inside the model-class.

最好在模型类内部。

回答by ivanhoe

I believe this is a perfect use-case for Eloquent events (http://laravel.com/docs/eloquent#model-events). You can use the "deleting" event to do the cleanup:

我相信这是 Eloquent 事件 ( http://laravel.com/docs/eloquent#model-events)的完美用例。您可以使用“删除”事件进行清理:

class User extends Eloquent
{
    public function photos()
    {
        return $this->has_many('Photo');
    }

    // this is a recommended way to declare event handlers
    public static function boot() {
        parent::boot();

        static::deleting(function($user) { // before delete() method call this
             $user->photos()->delete();
             // do the rest of the cleanup...
        });
    }
}

You should probably also put the whole thing inside a transaction, to ensure the referential integrity..

您可能还应该将整个事情放在一个事务中,以确保参照完整性。

回答by Chris Schmitz

You can actually set this up in your migrations:

您实际上可以在迁移中进行设置:

$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

Source: http://laravel.com/docs/5.1/migrations#foreign-key-constraints

来源:http: //laravel.com/docs/5.1/migrations#foreign-key-constraints

You may also specify the desired action for the "on delete" and "on update" properties of the constraint:

$table->foreign('user_id')
      ->references('id')->on('users')
      ->onDelete('cascade');

您还可以为约束的“删除时”和“更新时”属性指定所需的操作:

$table->foreign('user_id')
      ->references('id')->on('users')
      ->onDelete('cascade');

回答by akhy

Note: This answer was written for Laravel 3. Thus might or might not works well in more recent version of Laravel.

注意:此答案是为Laravel 3编写的。因此在更新的 Laravel 版本中可能会也可能不会很好地工作。

You can delete all related photos before actually deleting the user.

您可以在实际删除用户之前删除所有相关照片。

<?php

class User extends Eloquent
{

    public function photos()
    {
        return $this->has_many('Photo');
    }

    public function delete()
    {
        // delete all related photos 
        $this->photos()->delete();
        // as suggested by Dirk in comment,
        // it's an uglier alternative, but faster
        // Photo::where("user_id", $this->id)->delete()

        // delete the user
        return parent::delete();
    }
}

Hope it helps.

希望能帮助到你。

回答by Calin Blaga

Relation in User model:

用户模型中的关系:

public function photos()
{
    return $this->hasMany('Photo');
}

Delete record and related:

删除记录及相关:

$user = User::find($id);

// delete related   
$user->photos()->delete();

$user->delete();

回答by Paras

There are 3 approaches to solving this:

有3种方法可以解决这个问题:

1. Using Eloquent Events On Model Boot(ref: https://laravel.com/docs/5.7/eloquent#events)

1. 在模型启动时使用 Eloquent 事件(参考:https: //laravel.com/docs/5.7/eloquent#events

class User extends Eloquent
{
    public static function boot() {
        parent::boot();

        static::deleting(function($user) {
             $user->photos()->delete();
        });
    }
}

2. Using Eloquent Event Observers(ref: https://laravel.com/docs/5.7/eloquent#observers)

2. 使用 Eloquent Event Observers(参考:https: //laravel.com/docs/5.7/eloquent#observers

In your AppServiceProvider, register the observer like so:

在您的 AppServiceProvider 中,像这样注册观察者:

public function boot()
{
    User::observe(UserObserver::class);
}

Next, add an Observer class like so:

接下来,添加一个 Observer 类,如下所示:

class UserObserver
{
    public function deleting(User $user)
    {
         $user->photos()->delete();
    }
}

3. Using Foreign Key Constraints(ref: https://laravel.com/docs/5.7/migrations#foreign-key-constraints)

3. 使用外键约束(参考:https: //laravel.com/docs/5.7/migrations#foreign-key-constraints

$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

回答by Attila Fulop

As of Laravel 5.2, the documentation statesthat these kinds of event handlers should be registered in the AppServiceProvider:

从 Laravel 5.2 开始,文档指出这些类型的事件处理程序应该在 AppServiceProvider 中注册:

<?php
class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        User::deleting(function ($user) {
            $user->photos()->delete();
        });
    }

I even suppose to move them to separate classes instead of closures for better application structure.

我什至想将它们移动到单独的类而不是闭包以获得更好的应用程序结构。

回答by Ranga Lakshitha

It is better if you override the deletemethod for this. That way, you can incorporate DB transactions within the deletemethod itself. If you use the event way, you will have to cover your call of deletemethod with a DB transaction every time you call it.

最好delete为此重写该方法。这样,您就可以将 DB 事务合并到delete方法本身中。如果您使用事件方式,则delete每次调用它时都必须用数据库事务覆盖您的方法调用。

In your Usermodel.

在你的User模型中。

public function delete()
{
    \DB::beginTransaction();

     $this
        ->photo()
        ->delete()
    ;

    $result = parent::delete();

    \DB::commit();

    return $result;
}

回答by Carlos A. Carneiro

I would iterate through the collection detaching everything before deleting the object itself.

在删除对象本身之前,我会遍历集合以分离所有内容。

here's an example:

这是一个例子:

try {
        $user = user::findOrFail($id);
        if ($user->has('photos')) {
            foreach ($user->photos as $photo) {

                $user->photos()->detach($photo);
            }
        }
        $user->delete();
        return 'User deleted';
    } catch (Exception $e) {
        dd($e);
    }

I know it is not automatic but it is very simple.

我知道这不是自动的,但它非常简单。

Another simple approach would be to provide the model with a method. Like this:

另一种简单的方法是为模型提供一种方法。像这样:

public function detach(){
       try {

            if ($this->has('photos')) {
                foreach ($this->photos as $photo) {

                    $this->photos()->detach($photo);
                }
            }

        } catch (Exception $e) {
            dd($e);
        }
}

Then you can simply call this where you need:

然后你可以简单地在你需要的地方调用它:

$user->detach();
$user->delete();

回答by Alex

In my case it was pretty simple because my database tables are InnoDB with foreign keys with Cascade on Delete.

就我而言,这非常简单,因为我的数据库表是带有外键的 InnoDB,删除时带有级联。

So in this case if your photos table contains a foreign key reference for the user than all you have to do is to delete the hotel and the cleanup will be done by the Data Base, the data base will delete all the photos records from the data base.

因此,在这种情况下,如果您的照片表包含用户的外键引用,那么您所要做的就是删除酒店,清理工作将由数据库完成,数据库将从数据中删除所有照片记录根据。

回答by Darren Powers

Or you can do this if you wanted, just another option:

或者您可以根据需要执行此操作,只是另一种选择:

try {
    DB::connection()->pdo->beginTransaction();

    $photos = Photo::where('user_id', '=', $user_id)->delete(); // Delete all photos for user
    $user = Geofence::where('id', '=', $user_id)->delete(); // Delete users

    DB::connection()->pdo->commit();

}catch(\Laravel\Database\Exception $e) {
    DB::connection()->pdo->rollBack();
    Log::exception($e);
}

Note if you are not using the default laravel db connection then you need to do the following:

请注意,如果您没有使用默认的 laravel db 连接,那么您需要执行以下操作:

DB::connection('connection_name')->pdo->beginTransaction();
DB::connection('connection_name')->pdo->commit();
DB::connection('connection_name')->pdo->rollBack();