Laravel 如何能做到有效及优雅地进行批量UPDATE?

我的情况是,我想用 SortableJS/Sortable 做菜单/导航管理

功能及效果已经完成了,只不过我用了很愚蠢的方法,很不优雅的代码去做

database tabe menu

id (int) PK
fid (int) //父级id
name (int)
sort (int) //排序

Model中做了个子项目的function

//Models/Menu.php
public function  childs() {
    return  $this->hasMany(Menu::class, 'fid', 'id');
}

现在js一般都是用json 返回消息的
那么我会先
$menus = json_decode($request->menus, true);

dd($menus)得到以下内容:

array:2 [0 => array:2 ["id" => "5"
    "children" => array:4 [0 => array:2 ["id" => "6"
        "children" => []
      ]
      1 => array:2 ["id" => "7"
        "children" => []
      ]
      2 => array:2 ["id" => "8"
        "children" => []
      ]
      3 => array:2 ["id" => "9"
        "children" => []
      ]
    ]
  ]
  1 => array:2 ["id" => "1"
    "children" => array:3 [0 => array:2 ["id" => "3"
        "children" => []
      ]
      1 => array:2 ["id" => "4"
        "children" => []
      ]
      2 => array:2 ["id" => "2"
        "children" => []
      ]
    ]
  ]
]

我用了个极为愚蠢的方法来先让他有效

$sql = '';
foreach ($menus as $k => $v) {
    $id = $v['id'];
    $sql .= "UPDATE `menu` SET `fid` = 0 ,`sort` ='$k' WHERE `menu`.`id` = '$id';";

        if ($v['children']) {
            foreach ($v['children'] as $children_k => $children_v) {
                $children_id = $children_v['id'];
                $sql .= "UPDATE `menu` SET `fid` = '$id' ,`sort` ='$children_k' WHERE `menu`.`id` = '$children_id';";
                }
        }
}
DB::unprepared($sql);

不知各位有什么高见?
不能用Eloquent去做就算了,但竟然要用到unprepared(),感觉自己技术还是十分不行,想来请各位指点一二

顺带一提,在显示时,orderBy('sort','ASC')当然是没问题的,但是子项目却不行,我只能在blade做了,这个地方有什么更聪明的吗?

$row = Menu::where('fid', 0)->orderBy('sort', 'ASC')->get();
@foreach($row as $menu)
<li data-id="{{ $menu->id  }}"> {{ $menu->name }}
@if(count($menu->childs))
  @foreach($childs->sortBy('sort')  as $child)
  .....
  @endforeach
 @endif
</li>
@endforeach

不是求代码:pray: 本来这功能就是给后台/管理级别的人使用,功能都实现了,即使效率慢一点也没关系,只是抱著好奇的心来讨教一下,有没有更安全、更聪明一点的方法去完成

《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
抄你码科技有限公司
最佳答案

文档上upsert()的方法踩过了吗?

快速入门《Laravel 9 中文文档》

2年前 评论
讨论数量: 4

childs() 里可以做排序

2年前 评论

创建模型基类,下面的 updateBatch 方法通过 case when 语句实现了一条语句批量更新多条记录

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model as EloquentModel;
use Illuminate\Support\Facades\DB;

/**
 * Model 基类
 *
 * @author brad <brader.wen@gmail.com>
 * @date 2022-03-02
 */
class Model extends EloquentModel
{
    /**
     * 创建时间
     */
    const CREATED_AT = 'created_at';

    /**
     * 更新时间
     */
    const UPDATED_AT = 'updated_at';

    /**
     * @var string 日期格式化
     */
    protected $dateFormat = 'U';

    /**
     * 时间字段返回格式【默认为Carbon对象】
     *
     * @var array
     */
    protected $casts = [
        'created_at' => 'timestamp',
        'updated_at' => 'timestamp',
    ];

    /**
     * @var array 不可操作字段
     */
    protected $guarded = [];

    /**
     * 存储
     *
     * @param array $args
     * @return Mixed
     */
    public function store(array $args)
    {
        if (empty($args)) {
            return false;
        }

        $model = new static($args);
        $model->save();

        return $model;
    }

    /**
     * 存储
     *
     * @param array $args
     * @return Mixed
     */
    protected function _insert(array $args)
    {
        if (empty($args)) {
            return false;
        }

        return DB::table($this->table)->insert($args);
    }

    /**
     * 批量更新
     *
     * @param array $inputs
     * @param string $where_field
     * @param string $when_field
     * @return mixed
     *
     * [['id' => 1, 'status' => 1], ['id' => 2, 'status' => 1]]
     *
     * update users set name =
     *    case
     *    when id = 1 then 'a'
     *    when id = 2 then 'b'
     * where id in (1,2);
     */
    public function updateBatch(array $inputs, $where_field = 'id', $when_field = 'id')
    {
        if (empty($inputs)) {
            throw new \InvalidArgumentException('The update data is empty.');
        }
        if (!($where = array_pluck($inputs, $where_field)) || !($when = array_pluck($inputs, $when_field))) {
            throw new \InvalidArgumentException('Missing update condition');
        }
        $when_arr = [];
        foreach ($inputs as $k => $input) {
            if (true == $this->timestamps && !is_null(static::UPDATED_AT)) {
                $input[static::UPDATED_AT] = time();
            }

            $when_val = $input[$when_field] ?? '';
            if (1 > strlen($when_val)) throw new \InvalidArgumentException('inputs when field must be require');
            foreach ($input as $key => $value) {
                if ($key == $when_field) continue;
                $when_arr[$key][] = "when {$when_field} = '{$when_val}' then '{$value}'";
            }
        }
        $build = DB::connection($this->getConnectionName())->table($this->getTable())->whereIn($where_field, $where);
        foreach ($when_arr as $key => &$item) {
            $item = DB::raw('case ' . implode(' ', $item) . ' end ');
        }
        return $build->update($when_arr);
    }

    /**
     * 批量创建
     *
     * @param array $inputs
     * @return bool
     */
    public function storeBatch(array $inputs)
    {
        if (true == $this->timestamps) {
            foreach ($inputs as $key => $input) {
                $time = time();
                if (!is_null(static::CREATED_AT)) {
                    $inputs[$key][static::CREATED_AT] = $time;
                }
                if (!is_null(static::UPDATED_AT)) {
                    $inputs[$key][static::UPDATED_AT] = $time;
                }
            }
        }
        $query = DB::connection($this->getConnectionName())->table($this->getTable());
        return $query->insert($inputs);
    }

    /**
     * Get the number of models to return per page.
     *
     * @return int
     */
    public function getPerPage()
    {
        return request('per_page', 20);
    }
}
2年前 评论
抄你码科技有限公司

文档上upsert()的方法踩过了吗?

快速入门《Laravel 9 中文文档》

2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!