【问题标题】:Laravel, eloquent and foreach in controllerLaravel, eloquent 和 foreach 在控制器中
【发布时间】:2020-02-28 15:52:44
【问题描述】:

我是 Laravel 的新手,我对一件事感到好奇。我有 3 个数据库表:帖子、cmets、回复。我想对每个进行简单的删除。但显然帖子有很多 cmets,而 cmets 有很多回复。整个事情就是关于这些回复。好像我联系不上他们。

我在表之间有正常的工作关系。


<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Post;
use App\Comment;
use App\Reply;
use App\Traffic;
use Image;
use Illuminate\Support\Facades\Storage;

class PostsController extends Controller
{

  //few others things here...

  public function destroy($id) //$id is an id of post
    {
        // Select Post and comments of post
        $post = Post::find($id);
        $comments = Comment::where('post_id', $id);        

        //remove image (working fine)
        Storage::delete('public/img/' . $post->image);

        // delete all replies of post comments <<< Here is the issue. Can I even do like this?
            foreach ($comments as $comment) {
                $post_comment_reply = Reply::where('comment_id', $comment->id);
                $post_comment_reply->delete();
            }

            // delete post record (working fine)
            $post->delete();

            //delete comments of post (working fine)
            $comments->delete();

            // return to user profile (working fine)
            return redirect('/home')->with('success', 'Post has been deleted');
    }

【问题讨论】:

  • 这在数据库级别应该是自动的

标签: laravel eloquent


【解决方案1】:

有一种更简单的方法可以做到这一点.. 如果您只是将数据库约束添加到回复表中的外键到评论..

$table->unsignedInteger('comment_id');

$table->foreign('comment_id')->references('id')->on('comments')
    ->onDelete('cascade');

最后一部分:onDelete('cascade') 确保删除评论后所有回复都将被删除 :) 因此您不必在应用层手动执行此操作。

让我知道这是否有意义:)

【讨论】:

  • 迁移回滚输入什么内容?
  • 如果这是您运行的最后一次迁移。然后php artisan migrate:rollback 将删除该表,然后php artisan migrate 将再次创建它。否则,只需添加一个新的迁移,如果有外键,您将首先删除该外键,然后添加新的,如我在上面向您展示的那样。
  • 谢谢,回滚表并重新创建它是个好主意。
【解决方案2】:

您可以一次删除所有回复,而不是循环删除回复:

$comments = Comment::where('post_id', $id);
$comment_ids = $comments->pluck('id');

Reply::whereIn('comment_id', $comment_ids)->delete();

【讨论】:

    【解决方案3】:

    你的代码有什么问题是你创建了一个 db 查询但没有执行它:

    // You forgot the ->get() following the where statement
    foreach ($comments as $comment) 
        $post_comment_reply = Reply::where('comment_id', $comment->id)->get();
        $post_comment_reply->delete();
    }
    

    但是代码完全不是最优的,您可以使用 onDelete('cascade') 直接在数据库级别上创建它,或者只是创建一个删除回复的请求而不检索它们并减少对数据库的查询次数,像这样:

    foreach ($comments as $comment) 
        Reply::where('comment_id', $comment->id)->delete();
    }
    

    进一步减少上述建议的数据库查询:

    Reply::whereIn('comment_id', $comments->pluck('id'))->delete();
    

    【讨论】:

    • 是的,我确认最后一个它正在工作。但现在我正在考虑在数据库级别上执行此操作,如 Nakov 所示。谢谢!
    • 我写的不是数据库级别的删除。 nakov 的答案是数据库级别的删除。我希望你能理解其中的区别。
    【解决方案4】:

    如果你想通过 Laravel 删除关系,你必须重写 boot 函数。

    在您的 Comment 模型上覆盖 boot(),例如

    protected static function boot()
        {
            static::deleting(function (Comment $model) {
                $model->replies()->delete();
            });
    
            parent::boot();
        }
    

    当通过 eloquent 删除评论时,这将删除与评论关联的所有回复。

    【讨论】:

    • 我这样使用它只是因为我想要更多地控制删除。数据库级联删除绝对是您应该考虑的选项。
    猜你喜欢
    • 1970-01-01
    • 2012-11-28
    • 2014-08-08
    • 2021-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多