Подтвердить что ты не робот

Массовое обновление модели Eloquent

Пожалуйста, поправьте меня, если я ошибаюсь, но я думаю, что в модели Eloquent нет массовых обновлений.

Есть ли способ сделать массовое обновление таблицы БД без выдачи запроса для каждой строки?

Например, есть ли статический метод, что-то вроде

User::updateWhere(
    array('age', '<', '18'),
    array(
        'under_18' => 1 
        [, ...]
    )
);

(да, это глупый пример, но вы получите картину...)

Почему не реализована такая функция? Я единственный, кто был бы очень счастлив, если бы что-то подобное появилось?

Я (разработчики) не хотел бы реализовывать это так:

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

потому что по мере роста проекта мы можем потребовать от программистов изменить имя таблицы в будущем, и они не смогут искать и заменять имя таблицы!

Есть ли такой статический метод для выполнения этой операции? А если нет, можем ли мы расширить класс Illuminate\Database\Eloquent\Model для достижения такой цели?

4b9b3361

Ответ 1

Для массового обновления/вставки функций было запрошено, но Тейлор Отуэлл (автор Laravel) предлагает, чтобы пользователи вместо этого использовали Query Builder. https://github.com/laravel/framework/issues/1295

Ваши модели должны, как правило, расширять Illuminate\Database\Eloquent\Model. Затем вы получаете доступ к сущности, например, если у вас есть это:

<?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 ...

Обновление # 2

Вам нужно прибегнуть к построителю запросов. Чтобы охватить проблему с именами таблиц, вы можете получить ее динамически с помощью метода getTable(). Единственным ограничением этого является то, что вам нужно, чтобы ваш пользовательский класс инициализировался, прежде чем вы сможете использовать эту функцию. Ваш запрос будет выглядеть следующим образом:

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

Таким образом, ваше имя таблицы является контроллером в модели пользователя (как показано в примере выше).

Обновление # 1

Другой способ сделать это (неэффективно в вашей ситуации):

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

Таким образом, имя таблицы хранится в классе пользователей, и ваши разработчики не должны беспокоиться об этом.

Ответ 2

Возможно, это было невозможно несколько лет назад, но в последних версиях Laravel вы можете определенно сделать:

User::where('age', '<', 18)->update(['under_18' => 1]);

Стоит отметить, что вам нужен метод where перед вызовом update.

Ответ 3

Используйте транзакции базы данных для обновления нескольких объектов в массе. Транзакция будет зафиксирована, когда ваша функция обновления будет завершена, или откатится, если между ними возникла исключительная ситуация.

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,
                    ]);
            }
        });
    }

Ответ 4

Небольшая поправка к ответу @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();

Теперь вы можете иметь 1 миллион различных обновлений в одной транзакции БД

Ответ 5

Laravel 5.8 вы можете выполнить массовое обновление следующим образом:

User::where('id', 24)->update (dataAssociativeArray) ;