web-dev-qa-db-ja.com

説得力のあるモデルの一括更新

間違っている場合は修正してください。しかし、Eloquentモデルには大量更新などはないと思います。

すべての行に対してクエリを発行せずにDBテーブルを一括更新する方法はありますか?

たとえば、次のような静的メソッドがあります

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

(はい、それはばかげた例ですが、あなたは絵を手に入れます...)

なぜそのような機能が実装されていないのですか?このようなことが起こった場合、私は非常に幸せになるだろうか?

私(開発者)は、次のように実装したくありません。

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

プロジェクトが大きくなると、プログラマーが将来テーブル名を変更する必要があり、テーブル名を検索して置換できないためです!

この操作を実行する静的な方法はありますか?存在しない場合は、Illuminate\Database\Eloquent\Modelそのようなことを達成するクラス?

37
papas-source

大量の更新/挿入機能については、それが要求されましたが、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 ...

#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();
}

このように、テーブル名はユーザークラスに保持され、開発者はそれを心配する必要がありません。

45
phoops

おそらくこれは数年前には不可能でしたが、Laravelの最近のバージョンでは間違いなく次のことができます:

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

updateを呼び出す前にwhereメソッドが必要であることに注意してください。

50
bryceadams

データベーストランザクションを使用して、複数のエンティティを一括で更新します。トランザクションは、更新機能が終了したときにコミットされるか、例外がその間に発生した場合はロールバックされます。

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

たとえば、これは、1回の一括更新で記事のマテリアライズドパスナメクジ( 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,
                    ]);
            }
        });
    }
5
metamaker

@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つのDBトランザクションで1ミリオンの異なる更新を取得できるようになりました

4
catalin87

laravel 5.8では、次のように一括更新を実行できます。

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