Створення та оновлення красномовного Laravel


165

Що таке скорочення для вставки нового запису або оновлення, якщо воно існує?

<?php

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

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

Я здогадуюсь, shopIdце не ваш основний ключ, правда?
Сергій Паращів

@SergiuParaschiv, так. це не так
1myb

Перевірте відповідь від @ErikTheDeveloper. Він показує приємний красномовний метод, який повинен виконувати роботу.
cw24

Точно така ж річ повністю відповів на посилання нижче stackoverflow.com/questions/18839941 / ...
Bashirpour

Відповіді:


232

Ось повний приклад того, про що говорив "lu cip":

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

Нижче наведено оновлене посилання документів, яке знаходиться на останній версії Laravel

Документи тут: оновлене посилання


1
точно! "firstOrNew" також існує в 4.0 (не згадується в документах)
younes0

2
Також ми можемо перевірити, що $ user є новим / отриманим, використовуючи if ($ user-> існує).
Ryu_hayabusa

1
@Ryu_hayabusa Це, швидше за все, спричинить перегони
Кріс Харрісон,

новий синтаксис, здається, є updateOrInsert (масив $ атрибутів, масив $ значень = []) у 5.5: github.com/laravel/framework/blob/5.5/src/Illuminate/Database/…
користувач1204214

86

Оновлено: 27 серпня 2014 р. - [ updateOrCreateВбудовано в ядро ​​...]

На всякий випадок, коли люди все-таки стикаються з цим ... Я дізнався через кілька тижнів після написання цього, що це насправді частина ядра Красномовлення Ларавеля ...

Копатись в еквівалентних методах. Ви можете побачити тут:

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

на: 570 та: 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;
    }

Старий відповідь нижче


Мені цікаво, чи є якась вбудована функція L4 для цього певним чином, наприклад:

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

Я створив цей метод кілька тижнів тому ...

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

Я сподіваюся, що це допомагає. Я хотів би побачити альтернативу цьому, якщо хтось має кому поділитися. @erikthedev_


Є і називається firstOrNew / firstsOrCreate
злочин

@malcolmhall Я оновив відповідь вище. Виявляється, красномовний має багато особливостей, які я вважав, що будую;; Завжди добре провести час, переглядаючи документи :)
Ерік Айбар

4.2.0 пакетиста (стабільний 2014/6/1) не містить updateOrCreate. Але можна реалізувати це, дивлячись на джерело. ModelName::firstOrNew(['param' => 'condition'])->fill(Input::get())->save();повинен це зробити.
bibstha

3
Просто слідкуйте за тим, що Laravel не виконує це як транзакцію, тому якщо у вас є унікальні ключі, а інший користувач створює його з тим самим ключем одночасно, ви можете отримати виняток. Я вважаю, що однією з переваг RedBeanPHP є такий тип речі, який робиться за транзакцію за вас.
мальхал

Дякуємо, що вказали на використання функції fill (), яка мені дуже допомогла!
Відпочинок на Кіпрі

70

Оновлення 2020 року

Як і у Laravel> = 5.3 , якщо комусь все ще цікаво, як це зробити простим способом. Його можна з допомогою: updateOrCreate().

Наприклад, для заданого питання ви можете використовувати щось на кшталт:

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

Вищевказаний код перевірятиме таблицю, представлену ShopMeta, яка, швидше за все, shop_metasне буде визначена в самій моделі

і він спробує знайти запис із

стовпчик shopId = $theID

і

стовпчик metadateKey = 2001

і якщо він знайде, він оновить стовпець shopOwnerзнайденого рядка до New One.

Якщо він знайде більше, ніж один рядок, що збігається, він оновить перший перший рядок, що означає, що має найнижчий рівень первинного id.

Якщо його взагалі не знайдено, він вставить новий рядок із:

shopId = $theID, metadateKey = 2001іshopOwner = New One

Примітка. Перевірте свою модель $fillableта зверніть на позов про те, що там визначено кожне ім’я стовпця, яке ви хочете вставити чи оновити, а стовпці відпочинку мають або значення за замовчуванням, або його idстовпець автоматично збільшується.

Інакше він видасть помилку під час виконання вищевказаного прикладу:

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

Оскільки було б поле, якому знадобиться значення під час вставки нового рядка, і це буде неможливо, оскільки або його не визначено, $fillableабо воно не має значення за замовчуванням.

Докладніше див. У Документації щодо Laravel за адресою: https://laravel.com/docs/5.3/eloquent

Одним із прикладів є:

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

що в значній мірі все очищає.

Оновлення запиту Builder

Хтось запитав, чи можна використовувати Query Builder в Laravel. Ось посилання на Builder запитів від документів Laravel.

Query Builder працює точно так само, як і красномовний, тому все, що відповідає красномовному, відповідає і Builder запитів. Тож для цього конкретного випадку просто використовуйте ту саму функцію з конструктором запитів, як:

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

Звичайно, не забудьте додати фасад БД:

use Illuminate\Support\Facades\DB;

АБО

use DB;

Я сподіваюся, що це допомагає


Як щодо конструктора запитів?
Небо

Що з цим? :)
Учень

Я хочу зробити те саме, що і з Builder Query. Не красномовна. Це можливо?
Небо

Оновлено мою відповідь, шукайте розділ "Оновлення будівельника запитів" у наведеній вище відповіді.
Учень

Я спробував DB :: table ('shop_metas') :: метод updateOrCreate, але це дало мені наступну помилку BadMethodCallException в рядку Macroable.php 59: Метод updateOrInsert не існує. Хоча я використовую БД;
Swapnil Shende

17

Функція збереження:

$shopOwner->save()

вже роби те, що хочеш ...

Код 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
Це не схоже на операцію з атомною вгору. Якщо це не так, це може спричинити перегони.
Еміль Вікстрьом

Цей код призначений для перевірки завантаження моделі з БД чи модель на основі пам'яті. Оновлення або створення потребує явного визначення ключових стовпців, щоб перевірити їх, і їх не можна виконувати неявно.
AMIB

17

firstOrNewстворить запис, якщо він не існує, і оновить рядок, якщо вона вже існує. Тут ви також можете використати updateOrCreateповний приклад

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

Якщо є рейс з Окленда до Сан-Дієго, встановіть ціну на 99 доларів. якщо не існує, створіть новий рядок

Довідковий документ тут: ( https://laravel.com/docs/5.5/eloquent )


7

Якщо вам потрібен той самий функціонал за допомогою DB, у Laravel >= 5.5ви можете використовувати:

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

або скорочена версія, коли $attributesі $valuesоднакова:

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

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

Потім внесіть зміни та збережіть. Зверніть увагу, що firstOrNew не робить вставку, якщо її не знайдено, якщо вам це потрібно, то її firstOrCreate.


2

Ще один варіант, якщо ваш ідентифікатор не збільшується, і ви знаєте, який слід вставити / оновити:

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

2

Як і метод firstOrCreate, updateOrCreate зберігає модель, тому не потрібно викликати 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]
);

І для вашого питання

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

1

Насправді firstOrCreate не буде оновлено у випадку, якщо реєстр вже існує в БД. Я трохи покращив рішення Еріка, оскільки мені фактично потрібно було оновити таблицю, яка має унікальні значення не лише для стовпця "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);
    }
}

Тоді ви використовуєте це так:

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

що було добре в тому, щоб це не робити: 1. Видаліть на основі ключа і 2. створіть нові значення. Це були ще 2 операції. це економити час на індексацію у разі створення та видалення?
Хафіз

1

як @JuanchoRamone, розміщений вище (дякую @Juancho), це дуже корисно для мене, але якщо ваші дані є масивом, ви повинні трохи змінити так:

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

Просто коротке зауваження, що це має бути оновленоOrCreate замість createOrUpdate
Джон Шипп

Гаразд, але якщо буде 1000 рядків, буде 1000 запитів?
Марсело Агімовель

0

Хіба це не те саме, що updateOrCreate ()?

Це схоже, але не те саме. UpdateOrCreate () працюватиме лише для одного рядка одночасно, що не дозволяє вставляти групу. InsertOnDuplicateKey буде працювати у багатьох рядках.

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


-2

перевірити, чи існує користувач чи ні. Якщо не вставити

$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           

Ласкаво просимо до SO.Перегляньте це " відповідь" для надання якісної відповіді. ---
thewaywewere

Будь ласка, позначте також і фреймворк, який ви використовуєте, php-версію, базу даних.
Джейсон Джослін

1
я використовую Laravel 5.4, php7 та mysql
Сабріна Абід

Sabrina Це не ідеальне рішення, оскільки функції вже існують у laravel для цього. Але ваше - загальне рішення
djangodude

Його старий шкільний метод laravel вже має для цього функцію. Дивіться вибрану відповідь
Saeed Ansari
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.