Creazione e aggiornamento di Laravel Eloquent


165

Qual è la scorciatoia per l'inserimento di un nuovo record o l'aggiornamento se esiste?

<?php

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

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

Immagino shopIdnon sia la tua chiave primaria, giusto?
Sergiu Paraschiv,

@SergiuParaschiv, sì. non è
1myb,

Controlla la risposta da @ErikTheDeveloper. Mostra un metodo eloquente incorporato che dovrebbe fare il lavoro.
c24,

La stessa identica cosa è completamente risolta in link qui sotto stackoverflow.com/questions/18839941/...
Bashirpour

Risposte:


232

Ecco un esempio completo di ciò di cui parlava "lu cip":

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

Di seguito è riportato il link aggiornato dei documenti che si trova sull'ultima versione di Laravel

Documenti qui: link aggiornato


1
Esattamente! 'firstOrNew' esiste anche in 4.0 (non menzionato nei documenti)
younes0

2
Inoltre possiamo verificare che $ user sia nuovo / recuperato usando if ($ user-> esiste).
Ryu_hayabusa,

1
@Ryu_hayabusa Ciò probabilmente causerebbe condizioni di gara
Chris Harrison,

la nuova sintassi sembra essere updateOrInsert (array $ attributi, array $ valori = []) in 5.5: github.com/laravel/framework/blob/5.5/src/Illuminate/Database/…
user1204214

86

Aggiornato: 27 ago 2014 - [ updateOrCreateBuilt in core ...]

Nel caso in cui le persone si imbattano ancora in questo ... Ho scoperto alcune settimane dopo averlo scritto, che in realtà fa parte del nucleo di Laravel Eloquent ...

Scavando nei metodi equivalenti di Eloquent. Puoi vedere qui:

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

su: 570 e: 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;
    }

Vecchia risposta di seguito


Mi chiedo se esiste una funzionalità L4 integrata per farlo in qualche modo come:

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

Ho creato questo metodo alcune settimane fa ...

// 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;
}

Spero che aiuti. Mi piacerebbe vedere un'alternativa a questo se qualcuno ne ha uno da condividere. @erikthedev_


C'è e si chiama firstOrNew / firstsOrCreate
malhal

@malcolmhall Ho aggiornato la risposta sopra. Si scopre che Eloquent ha molte caratteristiche che mi sono ritrovato a ricostruire;) Sempre bello passare un po 'di tempo a consultare i documenti :)
Erik Aybar,

4.2.0 di packagist (stabile 2014/6/1) non contiene updateOrCreate. Ma uno può implementarlo guardando la fonte. ModelName::firstOrNew(['param' => 'condition'])->fill(Input::get())->save();dovrebbe farlo.
bibstha,

3
Fai attenzione che Laravel non lo esegua come una transazione, quindi se hai chiavi univoche e un altro utente lo crea contemporaneamente con la stessa chiave, potresti ottenere un'eccezione. Credo che uno dei vantaggi di RedBeanPHP sia che questo tipo di cose viene fatto in una transazione per te.
Malhal,

Grazie per aver sottolineato l'uso di fill () Mi ha aiutato moltissimo!
Rilassarsi a Cipro il

70

Aggiornamento 2020

Come in Laravel> = 5.3 , se qualcuno è ancora curioso di farlo in modo semplice. La sua possibile utilizzando: updateOrCreate().

Ad esempio per le domande poste puoi usare qualcosa come:

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

Il codice sopra controlla la tabella rappresentata da ShopMeta, che sarà molto probabilmente shop_metasse non diversamente definito nel modello stesso

e proverà a trovare la voce con

colonna shopId = $theID

e

colonna metadateKey = 2001

e se lo trova, aggiornerà la colonna shopOwnerdella riga trovata in New One.

Se trova più di una riga corrispondente, aggiornerà la prima riga che significa che ha il primario più basso id.

Se non trovato affatto, inserirà una nuova riga con:

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

Avviso Controlla il tuo modello $fillablee fai causa per avere ogni nome di colonna definito lì che desideri inserire o aggiornare e le colonne restanti hanno un valore predefinito o la sua idcolonna auto incrementata.

Altrimenti genererà un errore durante l'esecuzione dell'esempio sopra:

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))'

Poiché ci sarebbe un campo che avrà bisogno di valore durante l'inserimento di una nuova riga e non sarà possibile in quanto non è definito in $fillableo non ha un valore predefinito.

Per ulteriori riferimenti, consultare la documentazione di Laravel all'indirizzo: https://laravel.com/docs/5.3/eloquent

Un esempio da lì è:

// 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]
);

che praticamente cancella tutto.

Aggiornamento del generatore di query

Qualcuno ha chiesto se è possibile utilizzare Query Builder in Laravel. Ecco il riferimento per Query Builder dai documenti di Laravel.

Query Builder funziona esattamente come Eloquent, quindi tutto ciò che è vero per Eloquent è vero anche per Query Builder. Quindi, per questo caso specifico, usa la stessa funzione con il tuo generatore di query in questo modo:

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

Naturalmente, non dimenticare di aggiungere la facciata DB:

use Illuminate\Support\Facades\DB;

O

use DB;

spero possa essere d'aiuto


Che ne dici di Query Builder?
Sky

Che ne pensi? :)
Principiante

Voglio fare la stessa cosa con Query Builder. Non eloquente. È possibile?
Sky

Aggiornato la mia risposta, cerca la sezione "Aggiornamento del generatore di query" nella risposta sopra.
Principiante

Ho provato il metodo DB :: table ('shop_metas') :: updateOrCreate ma questo mi dà il seguente errore BadMethodCallException nella riga 59 di Macroable.php: Il metodo updateOrInsert non esiste. Anche se uso DB;
Swapnil Shende,

17

Salva funzione:

$shopOwner->save()

fai già quello che vuoi ...

Codice Laravel:

    // 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
Non sembra un'operazione di inversione atomica. In caso contrario, ciò potrebbe causare condizioni di gara.
Emil Vikström,

Questo codice serve per verificare se il modello è caricato dal DB o è un modello basato sulla memoria. Aggiorna o Crea richiede una definizione esplicita delle colonne chiave da controllare e non può essere eseguita in modo implicito.
AMIB,

17

firstOrNewcreerà record se non esiste e aggiornando una riga se già esiste. Puoi anche usare updateOrCreatequi l'esempio completo

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

Se c'è un volo da Oakland a San Diego, imposta il prezzo a $ 99. se non esiste, crea una nuova riga

Documento di riferimento qui: ( https://laravel.com/docs/5.5/eloquent )


7

Se hai bisogno della stessa funzionalità usando il DB, in Laravel >= 5.5puoi usare:

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

o la versione abbreviata quando $attributes e $valuessono uguali:

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

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

Quindi apportare le modifiche e salvare. Nota: firstOrNew non esegue l'inserimento se non viene trovato, se necessario, quindi firstOrCreate.


2

Un'altra opzione se il tuo ID non è autoincrement e sai quale inserire / aggiornare:

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

2

Come il primo metodo ORCreate, updateOrCreate persiste il modello, quindi non è necessario chiamare save ()

// 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]
);

E per il tuo problema

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

1

In realtà firstOrCreate non si aggiornerebbe nel caso in cui il registro esistesse già nel DB. Ho migliorato un po 'la soluzione di Erik poiché in realtà avevo bisogno di aggiornare una tabella con valori univoci non solo per la colonna "id"

/**
 * 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);
    }
}

Quindi lo useresti in questo modo:

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

cosa buono nel non farlo: 1. Elimina in base alla chiave e 2. crea con nuovi valori. Erano ancora 2 operazioni. è per risparmiare tempo da indicizzare in caso di creazione ed eliminazione?
Hafiz

1

come @JuanchoRamone pubblicato sopra (grazie a @Juancho) è molto utile per me, ma se i tuoi dati sono array dovresti modificare un po 'come questo:

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

Solo una breve nota che dovrebbe essere updateOrCreate invece di createOrUpdate
John Shipp

Ok ma se ci sono 1000 righe, saranno in esecuzione 1000 query?
Marcelo Agimóvel,


-2

controlla se esiste un utente o meno. In caso contrario, inserire

$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           

Benvenuti in SO. Dai un'occhiata a questo how-to-answer per fornire una risposta di qualità. ---
thewaywewere

Si prega inoltre di taggare il framework che si sta utilizzando, versione php, database.
Jason Joslin,

1
sto usando Laravel 5.4, php7 e mysql
Sabrina Abid

Sabrina Non è una soluzione ideale in quanto esiste già una funzione in laravel per farlo. Ma la tua è una soluzione generale
djangodude,

Il suo metodo old school laravel ha già una funzione per questo. Vedi la risposta selezionata
Saeed Ansari
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.