雄辩的模型质量更新

pap*_*rce 41 php laravel eloquent laravel-4

如果我错了,请纠正我,但我认为在Eloquent模型中没有大规模更新这样的东西.

有没有办法在数据库表上进行批量更新而不为每一行发出查询?

例如,是否有静态方法,如

User::updateWhere(
    array('age', '<', '18'),
    array(
        'under_18' => 1 
        [, ...]
    )
);
Run Code Online (Sandbox Code Playgroud)

(是的,这是一个愚蠢的例子,但你得到的图片...)

为什么没有实现这样的功能?如果这样的事情出现,我是唯一一个会非常高兴的人吗?

我(开发人员),不喜欢实现它:

DB::table('users')->where('age', '<', '18')->update(array('under_18' => 1));
Run Code Online (Sandbox Code Playgroud)

因为随着项目的增长,我们可能会要求程序员将来更改表名,他们无法搜索和替换表名!

是否有这样的静态方法来执行此操作?如果没有,我们可以扩展Illuminate\Database\Eloquent\Model课程来完成这样的事情吗?

bry*_*ams 58

也许几年前这是不可能的,但在Laravel的最新版本中你绝对可以做到:

User::where('age', '<', 18)->update(['under_18' => 1]);
Run Code Online (Sandbox Code Playgroud)

值得注意的是,在调用之前需要where方法update.

  • 可以确认这一点,与Laravel 5.2一起工作,更加优雅和"雄辩"的解决方案. (5认同)
  • 这次真是万分感谢。我正在深入研究源代码以检查他们是否真的这样做了! (2认同)
  • 接受的答案已经过时,谷歌搜索“雄辩的批量更新”时的第一个结果是这个问题;所以我想这应该是公认的答案。 (2认同)

pho*_*ops 48

对于大规模更新/插入功能,它被要求,但Taylor Otwell(Laravel作者)建议用户应该使用查询生成器.https://github.com/laravel/framework/issues/1295

您的模型通常应该扩展Illuminate\Database\Eloquent\Model.然后你访问实体iself,例如,如果你有这个:

<?php
Use Illuminate\Database\Eloquent\Model;

class User extends Model {

    // table name defaults to "users" anyway, so this definition is only for
    // demonstration on how you can set a custom one
    protected $table = 'users';
    // ... code omited ...
Run Code Online (Sandbox Code Playgroud)

更新#2

您必须求助于查询构建器.要涵盖表命名问题,您可以通过getTable()方法动态获取它.唯一的限制是您需要在使用此功能之前初始化您的用户类.您的查询如下:

$userTable = (new User())->getTable();
DB::table($userTable)->where('age', '<', 18)->update(array('under_18' => 1));
Run Code Online (Sandbox Code Playgroud)

这样,您的表名称就是User模型中的控制器(如上例所示).

更新#1

其他方式(在您的情况下效率不高)将是:

$users = User::where('age', '<', 18)->get();
foreach ($users as $user) {
    $user->field = value;
    $user->save();
}
Run Code Online (Sandbox Code Playgroud)

这样,表名保存在用户类中,您的开发人员不必担心它.

  • 我很清楚你所描述的方法。我想我很清楚我想在数据库中使用一个查询来做这样一件微不足道的事情。想象一下,如果有大约 20K 行需要更新。按照你描述的方式,将执行 20K 查询。更不用说在内存中保存 20K 记录的开销了! (3认同)

Irf*_*ndy 8

如果您需要无条件更新所有数据,请尝试以下代码

Model::query()->update(['column1' => 0, 'column2' => 'New']);
Run Code Online (Sandbox Code Playgroud)

  • 这正是我所寻找的,通过批量编辑,我们并不总是需要使用 where() 语句。由于我们不能调用 update() 作为模型的静态方法( Users:update() ),这对我来说是有用的答案。简短而清晰。 (2认同)

小智 6

@metamaker答案的小修正:

DB::beginTransaction();
     // do all your updates here

        foreach ($users as $user) {

            $new_value = rand(1,10) // use your own criteria

            DB::table('users')
                ->where('id', '=', $user->id)
                ->update([
                    'status' => $new_value  // update your field(s) here
                ]);
        }
    // when done commit
DB::commit();
Run Code Online (Sandbox Code Playgroud)

现在,您可以在一个数据库事务中进行100万次不同的更新


met*_*ker 5

使用数据库事务来批量更新多个实体。更新功能完成后,将提交事务;如果在两者之间发生异常,则回滚事务。

https://laravel.com/docs/5.4/database#database-transactions

例如,这是在单个批量更新中为文章重新生成实例化路径段(https://communities.bmc.com/docs/DOC-9902)的方式:

public function regenerateDescendantsSlugs(Model $parent, $old_parent_slug)
    {
        $children = $parent->where('full_slug', 'like', "%/$old_parent_slug/%")->get();

        \DB::transaction(function () use ($children, $parent, $old_parent_slug) {
            /** @var Model $child */
            foreach ($children as $child) {
                $new_full_slug  = $this->regenerateSlug($parent, $child);
                $new_full_title = $this->regenerateTitle($parent, $child);

                \DB::table($parent->getTable())
                    ->where('full_slug', '=', $child->full_slug)
                    ->update([
                        'full_slug' => $new_full_slug,
                        'full_title' => $new_full_title,
                    ]);
            }
        });
    }
Run Code Online (Sandbox Code Playgroud)