web-dev-qa-db-de.com

Eloquentes Modell-Massenupdate

Bitte korrigieren Sie mich, wenn ich falsch liege, aber ich glaube, es gibt kein Massenupdate in einem eloquenten Modell.

Gibt es eine Möglichkeit, eine Massenaktualisierung für die DB-Tabelle durchzuführen, ohne für jede Zeile eine Abfrage auszustellen?

Gibt es zum Beispiel eine statische Methode? 

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

(Ja, es ist ein dummes Beispiel, aber Sie bekommen das Bild ...)

Warum ist eine solche Funktion nicht implementiert? Bin ich der einzige, der sich sehr freuen würde, wenn so etwas auftaucht?

Ich (die Entwickler) möchte es nicht gerne so implementieren:

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

da das Projekt mitwächst, müssen die Programmierer möglicherweise den Tabellennamen in der Zukunft ändern und der Tabellenname kann nicht gesucht und ersetzt werden!

Gibt es eine solche statische Methode, um diesen Vorgang auszuführen? Und wenn nicht, können wir die Klasse Illuminate\Database\Eloquent\Model erweitern, um so etwas zu erreichen?

29
papas-source

Für Massenaktualisierungs-/Einfügungsfunktionen wurde dies angefordert, aber Taylor Otwell (Laravel-Autor) schlägt vor, dass Benutzer stattdessen den Abfrage-Generator verwenden. https://github.com/laravel/framework/issues/1295

Ihre Modelle sollten im Allgemeinen Illuminate\Database\Eloquent\Model erweitern. Dann greifen Sie auf die Entität sich selbst zu, wenn Sie beispielsweise Folgendes haben:

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

Update # 2

Sie müssen auf den Query Builder zurückgreifen. Um das Problem bei der Benennung von Tabellen zu behandeln, können Sie es dynamisch über die getTable () -Methode erhalten. Die einzige Einschränkung ist, dass Sie Ihre Benutzerklasse initialisieren müssen, bevor Sie diese Funktion verwenden können. Ihre Frage wäre wie folgt:

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

Auf diese Weise ist Ihr Tabellenname Controller im Benutzermodell (wie im obigen Beispiel gezeigt).

Update Nr. 1

Eine andere Möglichkeit (dies ist in Ihrer Situation nicht effizient) wäre:

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

Auf diese Weise wird der Tabellenname in der Benutzerklasse beibehalten und Ihre Entwickler müssen sich nicht darum kümmern.

34
phoops

Möglicherweise war dies vor einigen Jahren nicht möglich, aber in den letzten Versionen von Laravel können Sie dies definitiv tun:

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

Beachten Sie, dass Sie die where-Methode benötigen, bevor Sie update aufrufen.

39
bryceadams

Verwenden Sie Datenbanktransaktionen, um mehrere Entitäten in einem Massenbestand zu aktualisieren. Die Transaktion wird festgeschrieben, wenn Ihre Aktualisierungsfunktion abgeschlossen ist, oder es wird ein Rollback ausgeführt, wenn eine Ausnahme dazwischen aufgetreten ist.

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

So regeneriere ich zum Beispiel materialisierte Pfade ( https://communities.bmc.com/docs/DOC-9902 ) für Artikel in einem einzigen Massenupdate:

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

Eine kleine Korrektur der @ Metamaker-Antwort:

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

Jetzt können Sie 1 Million verschiedene Aktualisierungen in einer DB-Transaktion durchführen

0
catalin87

mit laravel 5.8 können Sie ein Massenupdate wie folgt durchführen:

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