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당신의 기본 키가 아닌 것 같아요 ?
Sergiu Paraschiv

@SergiuParaschiv, 응. 그것은
1myb

@ErikTheDeveloper의 답변을 확인하십시오. 그것은 일을해야 멋진 내장 웅변 방법을 보여줍니다.
cw24

답변:


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

1
@Ryu_hayabusa 경쟁 조건을 야기 할 가능성이 있음
Chris Harrison

5.5에서 새로운 구문은 updateOrInsert (array $ attributes, array $ values ​​= []) 인 것 같습니다 : 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;
}

도움이 되길 바랍니다. 누군가 공유 할 것이 있다면 이것에 대한 대안을보고 싶습니다. 아리따움


거기에 있으며 firstOrNew / firstsOrCreate
malhal

@malcolmhall 위의 답변을 업데이트했습니다. ) 항상 좋은 워드 프로세서 : 검색 시간을 보내고, 그것은 밝혀 웅변은 나 자신이 재건 발견 한 것을 많은 기능이있다
에릭 아이바를

packagist의 4.2.0 (안정적인 2014/6/1)에는 updateOrCreate가 포함되어 있지 않습니다. 그러나 소스를 보면서 구현할 수 있습니다. ModelName::firstOrNew(['param' => 'condition'])->fill(Input::get())->save();해야합니다.
bibstha

3
Laravel이 트랜잭션으로 트랜잭션을 실행하지 않는지 확인하십시오. 고유 키가 있고 다른 사용자가 동일한 키를 사용하여 동시에 키를 생성하면 예외가 발생할 수 있습니다. RedBeanPHP의 장점 중 하나는 이러한 유형의 작업이 트랜잭션에서 수행된다는 것입니다.
malhal

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 = 2001shopOwner = 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]
);

거의 모든 것을 지 웁니다.

쿼리 빌더 업데이트

누군가 라 라벨에서 Query Builder를 사용할 수 있는지 물었다. 다음 은 Laravel 문서의 Query Builder에 대한 참조입니다.

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

어때요? :)
Learner

Query Builder에서 동일한 작업을 수행하려고합니다. 설득력이 없습니다. 가능합니까?
Sky

내 답변을 업데이트했습니다. 위 답변에서 "쿼리 작성기 업데이트"섹션을 찾으십시오.
Learner

DB :: table ( 'shop_metas') :: updateOrCreate 메서드를 시도했지만 Macroable.php 줄 59에서 BadMethodCallException 오류가 발생합니다. updateOrInsert 메서드가 없습니다. 비록 DB를 사용하지만;
Swapnil Shende

17

기능 저장 :

$shopOwner->save()

벌써 네가 원하는 걸 해

라 라벨 코드 :

    // 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
그것은 원자 upsert 연산처럼 보이지 않습니다. 그렇지 않으면 경쟁 조건이 발생할 수 있습니다.
Emil Vikström

이 코드는 모델이 DB에서로드되었는지 또는 메모리 기반 모델인지 확인하기위한 것입니다. 업데이트 또는 작성은 키 열의 명시 적 정의를 확인해야하며 내재적으로 수행 할 수 없습니다.
AMIB

17

firstOrNew존재하지 않는 경우 레코드를 작성하고 이미 존재하는 경우 행을 업데이트합니다. 당신은 또한 updateOrCreate여기 전체 예제를 사용할 수 있습니다

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

오클랜드 발 샌디에이고 행 항공편이 있다면, 가격을 $ 99로 설정하십시오. 존재하지 않는 경우 새 행을 작성하십시오.

여기에 참조 문서 : ( https://laravel.com/docs/5.5/eloquent )


7

를 사용하여 동일한 기능이 필요한 경우 DBLaravel에서 >= 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가 자동 증가하지 않고 삽입 / 업데이트 할 ID를 알고있는 경우 한 가지 추가 옵션 :

$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

실제로 firstOrCreate 는 레지스터가 이미 DB에 존재하는 경우 업데이트 하지 않습니다 . "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 가지 작업이었습니다. 작성 및 삭제시 색인 작성 시간을 절약 할 수 있습니까?
Hafiz

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 개의 쿼리가 실행됩니까?
Marcelo Agimóvel


-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에 오신 것을 환영합니다 . 양질의 답변을 제공 하는 방법에 대해 살펴보십시오 . ---
thewaywewe는

또한 사용중인 프레임 워크, PHP 버전, 데이터베이스에 태그를 지정하십시오.
Jason Joslin

1
나는 Laravel 5.4, php7 및 mysql을 사용하고 있습니다
Sabrina Abid

Sabrina 라 라벨에 이미 존재하는 기능이기 때문에 이상적인 솔루션은 아닙니다. 하지만 당신은 일반적인 솔루션입니다
djangodude

구식 방법 인 laravel은 이미이를위한 기능을 가지고 있습니다. 선택된 답변보기
Saeed Ansari
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.