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
}
1myb
quelle
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
Genau das
Bashirpour

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

weotch
quelle
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_

Erik Aybar
quelle
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

Lerner
quelle
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);
    }
lu cip
quelle
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 )

Saeed Ansari
quelle
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);
Sasa Blagojevic
quelle
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.

malhal
quelle
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();
vivoconunxino
quelle
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', ....]
);
Bashirpour
quelle
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
        )
);
Juancho Ramone
quelle
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);
    }
}
Duy Ngo
quelle
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
0

Ist das nicht dasselbe wie updateOrCreate ()?

Es ist ähnlich, aber nicht dasselbe. UpdateOrCreate () funktioniert jeweils nur für eine Zeile, die keine Masseneinfügung zulässt. InsertOnDuplicateKey funktioniert in vielen Zeilen.

https://github.com/yadakhov/insert-on-duplicate-key

Pax Exterminatus
quelle
-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           
Sabrina Abid
quelle
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