Membuat dan Memperbarui Laravel Eloquent

165

Apa singkatan untuk menyisipkan catatan baru atau memperbarui jika ada?

<?php

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

if ($shopOwner == null) {
    // Insert new record into database
} else {
    // Update the existing record
}
1myb
sumber
Saya kira shopIdini bukan kunci utama Anda, bukan?
Sergiu Paraschiv
@SergiuParaschiv, ya. itu bukan
1myb
Lihat jawabannya dari @ErikTheDeveloper. Ini menunjukkan metode fasih embeded bagus yang harus melakukan pekerjaan.
cw24
Hal yang sama persis dijawab sepenuhnya di tautan di bawah ini stackoverflow.com/questions/18839941/…
Bashirpour

Jawaban:

232

Berikut adalah contoh lengkap dari apa yang "lu cip" bicarakan:

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

Di bawah ini adalah tautan terbaru dari dokumen yang ada pada versi terbaru Laravel

Documents di sini: Tautan yang diperbarui

weotch
sumber
1
persis! 'firstOrNew' juga ada di 4.0 (tidak disebutkan dalam dokumen)
younes0
2
Kami juga dapat memeriksa $ user baru / diambil dengan menggunakan if ($ user-> ada).
Ryu_hayabusa
1
@Ryu_hayabusa Itu kemungkinan akan menyebabkan kondisi balapan
Chris Harrison
Sintaks baru tampaknya menjadi updateOrInsert (array $ attributes, array $ values ​​= []) di 5.5: github.com/laravel/framework/blob/5.5/src/Illuminate/Database/…
user1204214
86

Diperbarui: 27 Agustus 2014 - [ updateOrCreateDibangun menjadi inti ...]

Kalau-kalau ada orang masih menemukan ini ... Saya tahu beberapa minggu setelah menulis ini, bahwa ini sebenarnya bagian dari inti Llovel's Eloquent ...

Menggali metode setara Eloquent. Anda bisa lihat di sini:

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

pada: 570 dan: 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;
    }

Jawaban Lama Di Bawah Ini


Saya bertanya-tanya apakah ada fungsi L4 bawaan untuk melakukan ini dalam beberapa cara seperti:

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

Saya memang membuat metode ini beberapa minggu yang lalu ...

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

Saya harap itu membantu. Saya akan senang melihat alternatif untuk ini jika ada yang punya satu untuk dibagikan. @erikthedev_

Erik Aybar
sumber
Ada dan ini disebut firstOrNew / firstsOrCreate
malhal
@malcolmhall Saya sudah memperbarui jawaban di atas. Ternyata Eloquent memiliki banyak fitur yang saya temukan untuk saya bangun kembali;) Selalu menyenangkan menghabiskan waktu menelusuri dokumen :)
Erik Aybar
4.2.0 packagist (stable 2014/6/1) tidak mengandung updateOrCreate. Tetapi orang dapat mengimplementasikannya dengan melihat sumbernya. ModelName::firstOrNew(['param' => 'condition'])->fill(Input::get())->save();harus melakukannya.
bibstha
3
Perhatikan bahwa Laravel tidak menjalankannya sebagai transaksi, jadi jika Anda memiliki kunci unik dan pengguna lain membuatnya dengan kunci yang sama secara bersamaan, Anda mungkin akan mendapatkan pengecualian. Saya percaya bahwa salah satu kelebihan RedBeanPHP adalah jenis hal ini dilakukan dalam transaksi untuk Anda.
Malhal
Terima kasih telah menunjukkan penggunaan fill () Itu sangat membantu saya!
Bersantai Di Siprus
70

Pembaruan 2020

Seperti pada Laravel> = 5.3 , jika seseorang masih penasaran bagaimana melakukannya dengan cara mudah. Itu mungkin dengan menggunakan:updateOrCreate() .

Misalnya untuk pertanyaan yang diajukan, Anda dapat menggunakan sesuatu seperti:

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

Kode di atas akan memeriksa tabel yang diwakili oleh ShopMeta, yang kemungkinan besar akan terjadi shop_metas kecuali tidak ditentukan sebaliknya dalam model itu sendiri

dan akan mencoba menemukan entri dengan

kolom shopId = $theID

dan

kolom metadateKey = 2001

dan jika ditemukan maka akan memperbarui kolom shopOwnerbaris yang ditemukan keNew One .

Jika menemukan lebih dari satu baris yang cocok maka itu akan memperbarui baris pertama yang berarti yang memiliki primer terendah id .

Jika tidak ditemukan sama sekali maka akan memasukkan baris baru dengan:

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

Perhatikan Periksa model Anda untuk $fillabledan membuat tuntutan bahwa Anda memiliki setiap nama kolom yang ditetapkan di mana Anda ingin memasukkan atau memperbarui dan kolom istirahat memiliki nilai default atauid kolomnya otomatis bertambah satu.

Jika tidak, akan terjadi kesalahan saat menjalankan contoh di atas:

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

Karena akan ada beberapa bidang yang akan membutuhkan nilai saat memasukkan baris baru dan itu tidak akan mungkin karena itu tidak didefinisikan $fillableatau tidak memiliki nilai default.

Untuk referensi lebih lanjut silakan lihat Dokumentasi Laravel di: https://laravel.com/docs/5.3/eloquent

Salah satu contoh dari sana adalah:

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

yang cukup banyak membersihkan segalanya.

Pembaruan Pembuat Kueri

Seseorang bertanya apakah mungkin menggunakan Query Builder di Laravel. Berikut ini adalah referensi untuk Pembuat Kueri dari Laravel docs.

Query Builder bekerja persis sama dengan Eloquent sehingga segala sesuatu yang berlaku untuk Eloquent juga berlaku untuk Query Builder. Jadi untuk kasus khusus ini, cukup gunakan fungsi yang sama dengan pembuat kueri Anda seperti:

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

Tentu saja, jangan lupa menambahkan fasad DB:

use Illuminate\Support\Facades\DB;

ATAU

use DB;

Saya harap ini membantu

Pelajar
sumber
Bagaimana dengan pembuat kueri?
Langit
Bagaimana dengan itu? :)
Learner
Saya ingin melakukan hal yang sama dengan Query Builder. Tidak fasih. Apa itu mungkin?
Langit
Memperbarui jawaban saya, cari bagian "Pembaruan Pembuat Kueri" di jawaban di atas.
Learner
Saya mencoba DB :: table ('shop_metas') :: metode updateOrCreate tapi ini memberi saya kesalahan BadMethodCallException di Macroable.php baris 59: Metode updateOrInsert tidak ada. Meskipun saya menggunakan DB;
Swapnil Shende
17

Simpan fungsi:

$shopOwner->save()

sudah melakukan apa yang Anda inginkan ...

Kode 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);
    }
lu cip
sumber
6
Itu tidak terlihat seperti operasi tenaga atom. Jika tidak, ini dapat menyebabkan kondisi balapan.
Emil Vikström
Kode ini untuk memeriksa apakah model diambil dari DB atau merupakan Model Berbasis Memori. Perbarui atau Buat perlu definisi eksplisit dari kolom kunci yang akan diperiksa dan tidak dapat dilakukan secara implisit.
AMIB
17

firstOrNewakan membuat catatan jika tidak ada dan memperbarui baris jika sudah ada. Anda juga bisa menggunakan di updateOrCreatesini adalah contoh lengkapnya

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

Jika ada penerbangan dari Oakland ke San Diego, tetapkan harga menjadi $ 99. jika tidak ada buat baris baru

Referensi Doc di sini: ( https://laravel.com/docs/5.5/eloquent )

Saeed Ansari
sumber
7

Jika Anda membutuhkan fungsi yang sama menggunakan DB, di Laravel >= 5.5Anda dapat menggunakan:

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

atau versi steno kapan $attributesdan $valuessama:

DB::table('table_name')->updateOrInsert($values);
Sasa Blagojevic
sumber
6
$shopOwner = ShopMeta::firstOrNew(array('shopId' => $theID,'metadataKey' => 2001));

Kemudian buat perubahan dan simpan. Perhatikan bahwa firstOrNew baru tidak melakukan penyisipan jika tidak ditemukan, jika Anda memang membutuhkannya maka yang pertama OrCreate.

jahat
sumber
2

Satu lagi opsi jika id Anda bukan autoincrement dan Anda tahu mana yang harus dimasukkan / perbarui:

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

Seperti metodeOrCreate pertama, updateOrCreate tetap menggunakan model, jadi tidak perlu memanggil 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]
);

Dan untuk masalah Anda

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

Sebenarnya firstOrCreate tidak akan memperbarui jika register sudah ada di DB. Saya meningkatkan sedikit solusi Erik karena saya benar-benar perlu memperbarui tabel yang memiliki nilai unik tidak hanya untuk kolom "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);
    }
}

Maka Anda akan menggunakannya seperti ini:

Model::createOrUpdate(
        array(
    'id_a' => 1,
    'foo' => 'bar'
        ), array(
    'id_a' => 1
        )
);
Juancho Ramone
sumber
apa yang baik dalam tidak melakukan ini: 1. Hapus berdasarkan kunci, dan 2. buat dengan nilai-nilai baru. Ini masih 2 operasi. apakah itu untuk menghemat waktu untuk mengindeks jika terjadi penciptaan dan penghapusan?
Hafiz
1

seperti @JuanchoRamone yang diposting di atas (terima kasih @Juancho) itu sangat berguna bagi saya, tetapi jika data Anda adalah array, Anda harus memodifikasi sedikit seperti ini:

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
sumber
Hanya catatan singkat bahwa ini harus menjadi pembaruanOrCreate alih-alih createOrUpdate
John Shipp
OK tapi jika ada 1000 baris, itu akan menjalankan 1000 query?
Marcelo Agimóvel
0

Bukankah ini sama dengan updateOrCreate ()?

Mirip tapi tidak sama. PembaruanOrCreate () hanya akan berfungsi untuk satu baris pada satu waktu yang tidak memungkinkan penyisipan massal. InsertOnDuplicateKey akan bekerja pada banyak baris.

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

Pax Exterminatus
sumber
-2

periksa apakah ada pengguna atau tidak. Jika tidak disisipkan

$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
sumber
Selamat datang di SO. Lihatlah cara-jawaban ini untuk memberikan jawaban berkualitas. ---
thewaywewere
Harap juga memberi tag kerangka kerja yang Anda gunakan, versi php, basis data.
Jason Joslin
1
saya menggunakan Laravel 5.4, php7, dan mysql
Sabrina Abid
Sabrina Ini bukan solusi ideal karena fungsi sudah ada di laravel untuk melakukannya. Tapi itu adalah solusi umum
Djangodude
Laravel metode jadulnya sudah memiliki fungsi untuk ini. Lihat jawaban yang dipilih
Saeed Ansari