Laravel Eloquentの作成と更新


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あなたの主キーではないと思いますよね?
セルジュパラシフ2013

@SergiuParaschiv、うん。それはそうではありません
1myb 2013

@ErikTheDeveloperからの回答を確認してください。それは仕事をするべきである素晴らしい埋め込み雄弁な方法を示します。
cw24 2015

まったく同じことが、stackoverflow.com
questions / 18839941 /…の

回答:


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
また、if($ user-> exists)を使用して、$ userが新しい/取得されていることを確認できます。
Ryu_hayabusa 2014年

1
@Ryu_hayabusa競合状態が発生する可能性があります
Chris Harrison、

:新しい構文は5.5でupdateOrInsert(配列$属性、配列$値= [])であるように思わgithub.com/laravel/framework/blob/5.5/src/Illuminate/Database/...
user1204214

86

更新:2014年8月27日-[ updateOrCreateコアに組み込まれています...]

万が一人々がまだこれに遭遇している場合に備えて...これを書いてから数週間後に、これは実際にはLaravelのEloquentのコアの一部であることがわかりました...

Eloquentの同等のメソッドを掘り下げます。あなたはここで見ることができます:

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と呼ばれます
malhal 14

@malcolmhall上記の答えを更新しました。Eloquentには、自分で再構築していることに気付いた多くの機能があることがわかります;)ドキュメントを閲覧するのにしばらく時間を費やすのはいつも良いです:)
Erik Aybar '27

packagistの4.2.0(安定版2014/6/1)にはupdateOrCreateが含まれていません。しかし、ソースを見てそれを実装することができます。ModelName::firstOrNew(['param' => 'condition'])->fill(Input::get())->save();それを行う必要があります。
bibstha

3
Laravelはそれをトランザクションとして実行しないことに注意してください。一意のキーがあり、別のユーザーが同じキーで同時にそれを作成した場合、例外が発生する可能性があります。RedBeanPHPの利点の1つは、このタイプの処理がトランザクションで行われることです。
Malhal 2014年

fill()の使用について指摘していただきありがとうございます。
キプロスでリラックス15年

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 = $theIDmetadateKey = 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デフォルト値がないため不可能です。

詳細については、https://laravel.com/docs/5.3/eloquentにあるLaravelのドキュメントを参照してください

そこからの一例は:

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

すべてをほぼクリアにします。

クエリビルダーの更新

誰かがLaravelのQuery Builderを使用して可能かどうか尋ねました。これは、Laravel docsからのクエリビルダーのリファレンスです。

Query BuilderはEloquentとまったく同じように動作するため、Eloquentに当てはまるものはすべてQuery Builderにも当てはまります。したがって、この特定のケースでは、次のようにクエリビルダーで同じ関数を使用します。

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

もちろん、DBファサードを追加することを忘れないでください:

use Illuminate\Support\Facades\DB;

または

use DB;

それが役に立てば幸い


クエリビルダーはどうですか?
Sky

それはどうですか?:)
学習者は

クエリビルダーでも同じことを行いたいのですが。雄弁ではない。出来ますか?
Sky

私の回答を更新しました。上記の回答の「Query Builder Update」セクションを探してください。
学習者、

DB :: table( 'shop_metas'):: updateOrCreateメソッドを試しましたが、Macroable.php行59で次のエラーBadMethodCallExceptionが発生しました:メソッドupdateOrInsertが存在しません。私はDBを使用していますが、
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
これはアトミックなアップサート操作のようには見えません。そうでない場合、これは競合状態を引き起こす可能性があります。
EmilVikström15年

このコードは、モデルがDBから読み込まれているか、メモリベースのモデルであるかを確認するためのものです。更新または作成には、チェックするキー列の明示的な定義が必要であり、暗黙的に実行することはできません。
AMIB 2017

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

IDが自動インクリメントではなく、挿入/更新するオプションがわかっている場合のもう1つのオプション:

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

2

firstOrCreate方法と同様に、updateOrCreateは、モデルを持続する)ので、(保存コールする必要はありません

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

実際には、レジスタがDBにすでに存在する場合、firstOrCreate更新されません。列「id」だけでなく一意の値を持つテーブルを実際に更新する必要があったため、Erikのソリューションを少し改善しました

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

これはcreateOrUpdateではなくupdateOrCreateであることに注意してください
John Shipp

わかりましたが、1000行ある場合、1000クエリが実行されますか?
MarceloAgimóvel、2018


-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へようこそ。質の高い回答を提供するためのこのHow -to-Answerをご覧ください。---
thewaywere

使用しているフレームワーク、phpバージョン、データベースにもタグを付けてください。
Jason Joslin 2017

1
Laravel 5.4、php7、およびmysqlを使用しています
サブリナアビッド

サブリナ関数は既にlaravelに存在するため、理想的なソリューションではありません。しかし、あなたの一般的なソリューションです
djangodude

その旧式の方法であるララベルには、すでにこの機能があります。選択した回答を見る
Saeed Ansari
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.