Erstellen und Aktualisieren von Laravel Eloquent


164

Was ist die Abkürzung zum Einfügen eines neuen Datensatzes oder zum Aktualisieren, falls vorhanden?

<?php

$shopOwner = ShopMeta::where('shopId', '=', $theID)
    ->where('metadataKey', '=', 2001)->first();

if ($shopOwner == null) {
    // Insert new record into database
} else {
    // Update the existing record
}

Ich vermute, das shopIdist nicht dein Primärschlüssel, oder?
Sergiu Paraschiv

@SergiuParaschiv, yep. es ist nicht
1myb

Schauen Sie sich die Antwort von @ErikTheDeveloper an. Es zeigt eine schöne eingebettete beredte Methode, die den Job machen sollte.
CW24

Antworten:


232

Hier ist ein vollständiges Beispiel dafür, worüber "lu cip" sprach:

$user = User::firstOrNew(array('name' => Input::get('name')));
$user->foo = Input::get('foo');
$user->save();

Unten finden Sie den aktualisierten Link der Dokumente, die sich auf der neuesten Version von Laravel befinden

Docs hier: Aktualisierter Link


1
genau! 'firstOrNew' existiert auch in 4.0 (in den Dokumenten nicht erwähnt)
younes0

2
Wir können auch überprüfen, ob $ user neu ist / abgerufen wird, indem wir if ($ user-> existiert) verwenden.
Ryu_hayabusa

1
@ Ryu_hayabusa Das würde wahrscheinlich Rennbedingungen verursachen
Chris Harrison

Die neue Syntax scheint updateOrInsert (Array $ Attribute, Array $ Werte = []) in 5.5 zu sein: github.com/laravel/framework/blob/5.5/src/Illuminate/Database/…
user1204214

86

Aktualisiert: 27. August 2014 - [ updateOrCreateEingebaut in den Kern ...]

Nur für den Fall, dass die Leute immer noch darauf stoßen ... Ich habe ein paar Wochen nach dem Schreiben herausgefunden, dass dies tatsächlich Teil von Laravels Eloquent's Kern ist ...

Eintauchen in die äquivalenten Methoden von Eloquent. Sie können hier sehen:

https://github.com/laravel/framework/blob/4.2/src/Illuminate/Database/Eloquent/Model.php#L553

am: 570 und: 553

    /**
     * Create or update a record matching the attributes, and fill it with values.
     *
     * @param  array  $attributes
     * @param  array  $values
     * @return static
     */
    public static function updateOrCreate(array $attributes, array $values = array())
    {
        $instance = static::firstOrNew($attributes);

        $instance->fill($values)->save();

        return $instance;
    }

Alte Antwort unten


Ich frage mich, ob es eine eingebaute L4-Funktionalität gibt, um dies auf irgendeine Weise zu tun, wie zum Beispiel:

$row = DB::table('table')->where('id', '=', $id)->first();
// Fancy field => data assignments here
$row->save();

Ich habe diese Methode vor ein paar Wochen erstellt ...

// Within a Model extends Eloquent
public static function createOrUpdate($formatted_array) {
    $row = Model::find($formatted_array['id']);
    if ($row === null) {
        Model::create($formatted_array);
        Session::flash('footer_message', "CREATED");
    } else {
        $row->update($formatted_array);
        Session::flash('footer_message', "EXISITING");
    }
    $affected_row = Model::find($formatted_array['id']);
    return $affected_row;
}

Ich hoffe das hilft. Ich würde gerne eine Alternative dazu sehen, wenn jemand eine zu teilen hat. @erikthedev_


Es gibt und es heißt firstOrNew / firstsOrCreate
malhal

@malcolmhall Ich habe die Antwort oben aktualisiert. Es stellt sich heraus, dass Eloquent viele Funktionen hat, die ich neu aufgebaut habe;) Immer gut, um etwas Zeit damit zu verbringen, die Dokumente zu durchsuchen :)
Erik Aybar

Packagists 4.2.0 (stabil 2014/6/1) enthält kein updateOrCreate. Aber man kann es mit Blick auf die Quelle implementieren. ModelName::firstOrNew(['param' => 'condition'])->fill(Input::get())->save();Sollte es tun.
Bibstha

3
Beachten Sie nur, dass Laravel es nicht als Transaktion ausführt. Wenn Sie also eindeutige Schlüssel haben und ein anderer Benutzer es gleichzeitig mit demselben Schlüssel erstellt, kann dies zu einer Ausnahme führen. Ich glaube, dass einer der Vorteile von RedBeanPHP darin besteht, dass diese Art von Dingen in einer Transaktion für Sie erledigt wird.
Malhal

Vielen Dank für den Hinweis auf die Verwendung von fill (). Das hat mir sehr geholfen!
Entspannen in Zypern

70

2020 Update

Wie in Laravel> = 5.3 , wenn jemand noch neugierig ist, wie man das auf einfache Weise macht. Es ist möglich mit : updateOrCreate().

Zum Beispiel können Sie für gestellte Fragen etwas verwenden wie:

$matchThese = ['shopId'=>$theID,'metadataKey'=>2001];
ShopMeta::updateOrCreate($matchThese,['shopOwner'=>'New One']);

Der obige Code überprüft die von ShopMeta dargestellte Tabelle. Dies ist höchstwahrscheinlich der Fall, shop_metassofern im Modell selbst nichts anderes definiert ist

und es wird versuchen, einen Eintrag mit zu finden

Säule shopId = $theID

und

Säule metadateKey = 2001

und wenn es findet, wird die Spalte shopOwnerder gefundenen Zeile auf aktualisiert New One.

Wenn mehr als eine übereinstimmende Zeile gefunden wird, wird die allererste Zeile aktualisiert, dh die niedrigste Primärzeile id.

Wenn überhaupt nicht gefunden, wird eine neue Zeile eingefügt mit:

shopId = $theID, metadateKey = 2001undshopOwner = New One

Hinweis Überprüfen Sie Ihr Modell auf $fillableund stellen Sie sicher, dass dort jeder Spaltenname definiert ist, den Sie einfügen oder aktualisieren möchten, und dass Restspalten entweder einen Standardwert oder einen idautomatisch inkrementierten Spaltenwert haben.

Andernfalls wird beim Ausführen des obigen Beispiels ein Fehler ausgegeben:

Illuminate\Database\QueryException with message 'SQLSTATE[HY000]: General error: 1364 Field '...' doesn't have a default value (SQL: insert into `...` (`...`,.., `updated_at`, `created_at`) values (...,.., xxxx-xx-xx xx:xx:xx, xxxx-xx-xx xx:xx:xx))'

Da es ein Feld geben würde, das beim Einfügen einer neuen Zeile einen Wert benötigt, ist dies nicht möglich, da es entweder nicht in definiert ist $fillableoder keinen Standardwert hat.

Weitere Informationen finden Sie in der Laravel-Dokumentation unter: https://laravel.com/docs/5.3/eloquent

Ein Beispiel von dort ist:

// If there's a flight from Oakland to San Diego, set the price to $99.
// If no matching model exists, create one.
$flight = App\Flight::updateOrCreate(
    ['departure' => 'Oakland', 'destination' => 'San Diego'],
    ['price' => 99]
);

das klärt so ziemlich alles.

Update des Abfrage-Generators

Jemand hat gefragt, ob es möglich ist, Query Builder in Laravel zu verwenden. Hier finden Sie eine Referenz für Query Builder aus Laravel-Dokumenten.

Query Builder funktioniert genauso wie Eloquent, sodass alles, was für Eloquent gilt, auch für Query Builder gilt. Verwenden Sie für diesen speziellen Fall einfach dieselbe Funktion mit Ihrem Abfrage-Generator wie folgt:

$matchThese = array('shopId'=>$theID,'metadataKey'=>2001);
DB::table('shop_metas')::updateOrCreate($matchThese,['shopOwner'=>'New One']);

Vergessen Sie natürlich nicht, die DB-Fassade hinzuzufügen:

use Illuminate\Support\Facades\DB;

ODER

use DB;

Ich hoffe, es hilft


Wie wäre es mit Query Builder?
Himmel

Was ist damit ? :)
Lerner

Ich möchte dasselbe mit Query Builder tun. Nicht beredt. Ist es möglich?
Himmel

Meine Antwort wurde aktualisiert. Suchen Sie in der obigen Antwort nach dem Abschnitt "Query Builder Update".
Lerner

Ich habe versucht, DB :: table ('shop_metas') :: updateOrCreate-Methode, aber dies gibt mir folgenden Fehler BadMethodCallException in Macroable.php Zeile 59: Methode updateOrInsert existiert nicht. Obwohl ich DB benutze;
Swapnil Shende

17

Speicherfunktion:

$shopOwner->save()

mach schon was du willst ...

Laravel-Code:

    // If the model already exists in the database we can just update our record
    // that is already in this database using the current IDs in this "where"
    // clause to only update this model. Otherwise, we'll just insert them.
    if ($this->exists)
    {
        $saved = $this->performUpdate($query);
    }

    // If the model is brand new, we'll insert it into our database and set the
    // ID attribute on the model to the value of the newly inserted row's ID
    // which is typically an auto-increment value managed by the database.
    else
    {
        $saved = $this->performInsert($query);
    }

6
Das sieht nicht nach einer atomaren Upsert-Operation aus. Ist dies nicht der Fall, kann dies zu Rennbedingungen führen.
Emil Vikström

Mit diesem Code soll überprüft werden, ob das Modell aus der Datenbank geladen wurde oder ein speicherbasiertes Modell ist. Aktualisieren oder Erstellen erfordert eine explizite Definition der zu prüfenden Schlüsselspalten und kann nicht implizit ausgeführt werden.
AMIB

17

firstOrNewerstellt einen Datensatz, falls nicht vorhanden, und aktualisiert eine Zeile, falls bereits vorhanden. Sie können updateOrCreatehier auch das vollständige Beispiel verwenden

$flight = App\Flight::updateOrCreate(
    ['departure' => 'Oakland', 'destination' => 'San Diego'],
    ['price' => 99]
); 

Wenn es einen Flug von Oakland nach San Diego gibt, setzen Sie den Preis auf 99 US-Dollar. Wenn nicht vorhanden, erstellen Sie eine neue Zeile

Referenzdokument hier: ( https://laravel.com/docs/5.5/eloquent )


7

Wenn Sie dieselbe Funktionalität mit dem benötigen DB, können Sie in Laravel Folgendes >= 5.5verwenden:

DB::table('table_name')->updateOrInsert($attributes, $values);

oder die Kurzfassung, wenn $attributesund gleich $valuessind:

DB::table('table_name')->updateOrInsert($values);

6
$shopOwner = ShopMeta::firstOrNew(array('shopId' => $theID,'metadataKey' => 2001));

Nehmen Sie dann Ihre Änderungen vor und speichern Sie sie. Beachten Sie, dass firstOrNew das Einfügen nicht ausführt, wenn es nicht gefunden wird. Wenn Sie dies benötigen, ist es firstOrCreate.


2

Eine weitere Option, wenn Ihre ID nicht automatisch inkrementiert wird und Sie wissen, welche Sie einfügen / aktualisieren müssen:

$object = MyModel::findOrNew($id);
//assign attributes to update...
$object->save();

2

Wie die firstOrCreate-Methode behält updateOrCreate das Modell bei, sodass save () nicht aufgerufen werden muss.

// If there's a flight from Oakland to San Diego, set the price to $99.
// If no matching model exists, create one.

$flight = App\Flight::updateOrCreate(
   ['departure' => 'Oakland', 'destination' => 'San Diego'],
   ['price' => 99]
);

Und für Ihr Problem

$shopOwner = ShopMeta::updateOrCreate(
   ['shopId' => $theID, 'metadataKey' => '2001'],
   ['other field' => 'val' ,'other field' => 'val', ....]
);

1

Tatsächlich würde firstOrCreate nicht aktualisiert, falls das Register bereits in der Datenbank vorhanden ist. Ich habe Eriks Lösung ein wenig verbessert, da ich tatsächlich eine Tabelle aktualisieren musste, die eindeutige Werte nicht nur für die Spalte "id" enthält.

/**
 * If the register exists in the table, it updates it. 
 * Otherwise it creates it
 * @param array $data Data to Insert/Update
 * @param array $keys Keys to check for in the table
 * @return Object
 */
static function createOrUpdate($data, $keys) {
    $record = self::where($keys)->first();
    if (is_null($record)) {
        return self::create($data);
    } else {
        return self::where($keys)->update($data);
    }
}

Dann würden Sie es so verwenden:

Model::createOrUpdate(
        array(
    'id_a' => 1,
    'foo' => 'bar'
        ), array(
    'id_a' => 1
        )
);

Was war gut daran, dies nicht zu tun: 1. Löschen basierend auf dem Schlüssel und 2. Erstellen mit neuen Werten. Dies waren noch 2 Operationen. Ist es Zeit zu sparen, um beim Erstellen und Löschen zu indizieren?
Hafiz

1

Wie @JuanchoRamone oben gepostet (danke @Juancho) ist es sehr nützlich für mich, aber wenn Ihre Daten Array sind, sollten Sie ein wenig wie folgt ändern:

public static function createOrUpdate($data, $keys) {
    $record = self::where($keys)->first();
    if (is_null($record)) {
        return self::create($data);
    } else {
        return $record->update($data);
    }
}

Nur eine kurze Anmerkung, dass dies updateOrCreate anstelle von createOrUpdate sein sollte
John Shipp

Ok, aber wenn 1000 Zeilen vorhanden sind, werden 1000 Abfragen ausgeführt?
Marcelo Agimóvel


-2

Überprüfen Sie, ob ein Benutzer vorhanden ist oder nicht. Wenn nicht einfügen

$exist = DB::table('User')->where(['username'=>$username,'password'=>$password])->get();
if(count($exist)  >0) {
    echo "User already exist";;
}
else  {
    $data=array('username'=>$username,'password'=>$password);
    DB::table('User')->insert($data);
}
Laravel 5.4           

Willkommen bei SO. Sehen Sie sich diese Antwort an, um eine qualitativ hochwertige Antwort zu erhalten. ---
thewaywewere

Bitte kennzeichnen Sie auch das von Ihnen verwendete Framework, die PHP-Version und die Datenbank.
Jason Joslin

1
Ich benutze Laravel 5.4, PHP7 und MySQL
Sabrina Abid

Sabrina Es ist keine ideale Lösung, da bereits Funktionen in Laravel dafür existieren. Aber Ihre ist eine allgemeine Lösung
Djangodude

Die Old-School-Methode Laravel hat dafür bereits eine Funktion. Siehe ausgewählte Antwort
Saeed Ansari
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.