การสร้างและอัพเดต 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

สิ่งเดียวกันที่แน่นอนตอบอย่างสมบูรณ์ในลิงค์ด้านล่าง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 (ไม่ได้กล่าวถึงในเอกสาร)
0

2
นอกจากนี้เราสามารถตรวจสอบ $ ผู้ใช้ใหม่ / ดึงโดยใช้ถ้า ($ user-> มีอยู่)
Ryu_hayabusa

1
@Ryu_hayabusa นั่นอาจทำให้เกิดสภาพการแข่งขัน
Chris Harrison

ไวยากรณ์ใหม่ดูเหมือนว่าจะเป็น updateOrInsert (อาร์เรย์ $ attribute, อาร์เรย์ $ values ​​= []) ใน 5.5: github.com/laravel/framework/blob/5.5/src/Illuminate/Database/…
user1204214

86

อัปเดต: 27 ส.ค. 2557 - [ updateOrCreateสร้างเป็นแกนหลัก ... ]

ในกรณีที่ผู้คนยังคงเจอสิ่งนี้ ... ฉันค้นพบไม่กี่สัปดาห์หลังจากที่เขียนสิ่งนี้นี่เป็นความจริงในส่วนหลักของ Eloquent's Core ...

ขุดเป็นวิธีเทียบเท่าของ 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

@malcolmhall ฉันได้อัปเดตคำตอบข้างต้นแล้ว ปรากฎว่า Eloquent มีคุณสมบัติมากมายที่ฉันได้พบว่าตัวเองกำลังสร้างขึ้นมาใหม่;) ดีเสมอที่จะใช้เวลาในการเรียกดูเอกสาร :)
Erik Aybar

packagist's 4.2.0 (เสถียร 2014/6/25) ไม่มีการอัปเดตหรือสร้าง แต่สามารถนำไปใช้งานได้โดยดูจากแหล่งที่มา ModelName::firstOrNew(['param' => 'condition'])->fill(Input::get())->save();ควรทำมัน
bibstha

3
เพียงระวังว่า Laravel ไม่ได้เรียกใช้เป็นธุรกรรมดังนั้นหากคุณมีคีย์ที่ไม่ซ้ำกันและผู้ใช้รายอื่นสร้างขึ้นด้วยคีย์เดียวกันพร้อมกันคุณอาจได้รับข้อยกเว้น ฉันเชื่อว่าข้อดีอย่างหนึ่งของ RedBeanPHP คือการทำธุรกรรมประเภทนี้สำหรับคุณ
malhal

ขอบคุณสำหรับการชี้ให้เห็นถึงการใช้เติม () ที่ได้ช่วยฉันอย่างมาก!
ผ่อนคลายในไซปรัส

70

2563 ปรับปรุง

เช่นเดียวกับในLaravel> = 5.3หากใครบางคนยังสงสัยว่าจะทำอย่างไรในวิธีที่ง่าย เป็นไปได้โดยใช้: updateOrCreate().

ตัวอย่างเช่นคำถามที่ถามคุณสามารถใช้สิ่งที่ชอบ:

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

โค้ดด้านบนจะตรวจสอบตารางที่แสดงโดย ShopMeta ซึ่งจะเป็นไปได้มากที่สุดshop_metasเว้นแต่จะไม่ได้กำหนดไว้เป็นอย่างอื่นในโมเดล

และจะพยายามค้นหารายการด้วย

คอลัมน์ shopId = $theID

และ

คอลัมน์ metadateKey = 2001

และหากพบก็จะปรับปรุงคอลัมน์ของพบแถวshopOwnerNew 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]
);

ซึ่งค่อนข้างล้างทุกอย่าง

ปรับปรุงตัวสร้างแบบสอบถาม

มีคนถามว่าเป็นไปได้หรือไม่หากใช้ Query Builder ใน Laravel นี่คือการอ้างอิงสำหรับตัวสร้างแบบสอบถามจากเอกสาร Laravel

ตัวสร้างแบบสอบถามทำงานเหมือนกับ Eloquent ดังนั้นทุกอย่างที่เป็นจริงสำหรับ Eloquent นั้นเป็นจริงสำหรับตัวสร้างแบบสอบถามด้วยเช่นกัน ดังนั้นสำหรับกรณีเฉพาะนี้ให้ใช้ฟังก์ชันเดียวกันกับตัวสร้างคิวรีของคุณดังนี้

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

แน่นอนอย่าลืมเพิ่มซุ้มฐานข้อมูล:

use Illuminate\Support\Facades\DB;

หรือ

use DB;

ฉันหวังว่ามันจะช่วย


วิธีการเกี่ยวกับการสร้างแบบสอบถาม?
สกาย

แล้วมันล่ะ? :)
ผู้เรียน

ฉันต้องการทำสิ่งเดียวกันกับตัวสร้างแบบสอบถาม ไม่เก่ง เป็นไปได้ไหม?
ท้องฟ้า

อัปเดตคำตอบของฉันแล้วมองหาส่วน "ปรับปรุงตัวสร้างแบบสอบถาม" ในคำตอบด้านบน
ผู้เรียน

ฉันลอง DB :: table ('shop_metas') :: updateOrCreate แต่ตอนนี้ให้ฉันข้อผิดพลาด BadMethodCallException ใน Macroable.php บรรทัด 59: วิธีการ 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
ที่ดูเหมือนว่าการดำเนินการเพิ่มขึ้นของอะตอม หากไม่เป็นเช่นนี้อาจทำให้เกิดสภาพการแข่งขัน
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

หากคุณต้องการฟังก์ชันการทำงานเดียวกันโดยใช้ตัวเลือก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));

จากนั้นทำการเปลี่ยนแปลงและบันทึกของคุณ หมายเหตุแรกหรือใหม่จะไม่ทำการแทรกถ้าไม่พบถ้าคุณต้องการมันก่อนหรือสร้างขึ้น


2

อีกหนึ่งทางเลือกถ้ารหัสของคุณไม่ได้ถูกสร้างขึ้นโดยอัตโนมัติและคุณรู้ว่าควรจะใส่ / อัพเดตตัวใด

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

2

เช่นเดียวกับวิธีแรกหรือสร้างการอัปเดตหรือสร้างยังคงรูปแบบดังนั้นไม่จำเป็นต้องโทร 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

ที่จริงก่อนหรือสร้างจะไม่อัปเดตในกรณีที่การลงทะเบียนมีอยู่แล้วในฐานข้อมูล ฉันปรับปรุงโซลูชันของ Erik สักเล็กน้อยเนื่องจากฉันต้องการปรับปรุงตารางที่มีค่าไม่ซ้ำกันไม่เพียง แต่สำหรับคอลัมน์ "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);
    }
}

เพียงทราบอย่างรวดเร็วว่าควรอัปเดตหรือสร้างแทน createOrUpdate
John Shipp

ตกลง แต่ถ้ามี 1,000 แถวจะมี 1,000 ข้อความค้นหาทำงานหรือไม่
Marcelo Agimóvel

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.Take ดูที่วิธีการตอบสำหรับการให้คำตอบที่มีคุณภาพนี้ ---
ทุก

โปรดติดแท็กเฟรมเวิร์กที่คุณใช้, รุ่น php, ฐานข้อมูล
Jason Joslin

1
ฉันใช้ Laravel 5.4, php7 และ mysql
Sabrina Abid

ซาบรินาไม่ใช่ทางออกที่ดีเพราะฟังก์ชั่นมีอยู่แล้วใน laravel สำหรับการทำเช่นนั้น แต่ของคุณเป็นคำตอบทั่วไป
djangodude

วิธีการเรียนแบบเก่าของมันมีฟังก์ชั่นนี้แล้ว ดูคำตอบที่เลือก
Saeed Ansari
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.