Tạo và cập nhật Laravel Eloquent


165

Tốc ký để chèn một bản ghi mới hoặc cập nhật nếu nó tồn tại là gì?

<?php

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

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

Tôi đoán shopIdkhông phải là khóa chính của bạn, phải không?
Sergiu Paraschiv

@SergiuParachiv, vâng. không phải vậy
1myb

Kiểm tra câu trả lời từ @ErikTheDeveloper. Nó cho thấy một phương pháp hùng biện nhúng tốt đẹp nên thực hiện công việc.
cw24

Điều tương tự chính xác được trả lời đầy đủ trong liên kết bên dưới stackoverflow.com/questions/18839941/
Khăn

Câu trả lời:


232

Đây là một ví dụ đầy đủ về những gì "lu cip" đã nói về:

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

Dưới đây là liên kết được cập nhật của các tài liệu trên phiên bản mới nhất của Laravel

Tài liệu ở đây: Liên kết cập nhật


1
chính xác! 'FirstOrNew' cũng tồn tại trong 4.0 (không được đề cập trong các tài liệu)
younes0

2
Ngoài ra, chúng tôi có thể kiểm tra $ user là mới / được truy xuất bằng cách sử dụng if ($ user-> tồn tại).
Ryu_hayabusa

1
@Ryu_hayabusa Điều đó có thể gây ra tình trạng chủng tộc
Chris Harrison

cú pháp mới dường như được cập nhậtOrInsert (mảng $ thuộc tính, mảng $ value = []) trong 5.5: github.com/laravel/framework/blob/5.5/src/Illuminate/Database/
trộm

86

Cập nhật: 27 tháng 8 năm 2014 - [ updateOrCreateĐược xây dựng vào cốt lõi ...]

Chỉ trong trường hợp mọi người vẫn bắt gặp điều này ... Tôi đã phát hiện ra một vài tuần sau khi viết bài này, rằng đây thực sự là một phần trong cốt lõi của Eloquent của Laravel ...

Đi sâu vào (các) phương pháp tương đương của Eloquent. Bạn có thể thấy ở đây:

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

trên: 570 và: 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;
    }

Câu trả lời cũ dưới đây


Tôi tự hỏi nếu có bất kỳ chức năng L4 tích hợp nào để thực hiện việc này theo một cách nào đó như:

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

Tôi đã tạo ra phương pháp này một vài tuần trước ...

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

Tôi hy vọng rằng sẽ giúp. Tôi rất muốn thấy một sự thay thế cho điều này nếu bất cứ ai có một để chia sẻ. @erikthedev_


Có và nó được gọi là FirstOrNew / FirstsOrCreate
malhal

@malcolmhall Tôi đã cập nhật câu trả lời ở trên. Hóa ra Eloquent có nhiều tính năng mà tôi thấy mình đang xây dựng lại;) Luôn luôn tốt để dành thời gian duyệt các tài liệu :)
Erik Aybar

4.2.0 (ổn định 2014/6/1) của packagist không chứa updateOrCreate. Nhưng người ta có thể thực hiện nó nhìn vào nguồn. ModelName::firstOrNew(['param' => 'condition'])->fill(Input::get())->save();Hãy làm nó.
bibstha

3
Chỉ cần xem ra rằng Laravel không chạy nó như một giao dịch, vì vậy nếu bạn có các khóa duy nhất và một người dùng khác tạo nó với cùng một khóa đồng thời bạn có thể gặp ngoại lệ. Tôi tin rằng một trong những lợi thế của RedBeanPHP là loại điều này được thực hiện trong một giao dịch cho bạn.
malhal

Cảm ơn đã chỉ ra việc sử dụng fill () Điều đó đã hỗ trợ tôi rất nhiều!
Thư giãn tại Síp

70

Cập nhật 2020

Như trong Laravel> = 5.3 , nếu ai đó vẫn tò mò làm thế nào để làm điều đó một cách dễ dàng. Nó có thể bằng cách sử dụng : updateOrCreate().

Ví dụ cho câu hỏi được hỏi, bạn có thể sử dụng một cái gì đó như:

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

Mã ở trên sẽ kiểm tra bảng được đại diện bởi ShopMeta, rất có thể sẽ shop_metastrừ khi không được định nghĩa khác trong chính mô hình

và nó sẽ cố gắng tìm mục với

cột shopId = $theID

cột metadateKey = 2001

và nếu tìm thấy thì nó sẽ cập nhật cột shopOwnercủa hàng tìm thấy thành New One.

Nếu nó tìm thấy nhiều hơn một hàng phù hợp thì nó sẽ cập nhật hàng đầu tiên có nghĩa là có hàng chính thấp nhất id.

Nếu hoàn toàn không tìm thấy thì nó sẽ chèn một hàng mới với:

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

Lưu ý Kiểm tra mô hình của bạn $fillablevà thực hiện kiện rằng bạn có mọi tên cột được xác định tại đó bạn muốn chèn hoặc cập nhật và các cột còn lại có giá trị mặc định hoặc idcột tự động tăng lên.

Nếu không, nó sẽ ném lỗi khi thực hiện ví dụ trên:

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

Vì sẽ có một số trường sẽ cần giá trị trong khi chèn hàng mới và nó sẽ không thể thực hiện được vì nó không được xác định trong $fillablehoặc nó không có giá trị mặc định.

Để tham khảo thêm, vui lòng xem Tài liệu của Laravel tại: https://laravel.com/docs/5.3/eloquent

Một ví dụ từ đó là:

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

mà khá nhiều xóa tất cả mọi thứ.

Cập nhật Trình tạo truy vấn

Ai đó đã hỏi liệu có thể sử dụng Query Builder trong Laravel không. Đây là tài liệu tham khảo cho Trình tạo truy vấn từ các tài liệu của Laravel.

Trình tạo truy vấn hoạt động chính xác giống như Eloquent, vì vậy mọi thứ đúng với Eloquent đều đúng với Trình tạo truy vấn. Vì vậy, đối với trường hợp cụ thể này, chỉ cần sử dụng cùng chức năng với trình tạo truy vấn của bạn như vậy:

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

Tất nhiên, đừng quên thêm mặt tiền DB:

use Illuminate\Support\Facades\DB;

HOẶC LÀ

use DB;

Tôi hy vọng nó sẽ giúp


Làm thế nào về xây dựng truy vấn?
Bầu trời

Còn nó thì sao ? :)
Người học

Tôi muốn làm điều tương tự với Trình tạo truy vấn. Không hiệu quả. Có thể không?
Bầu trời

Đã cập nhật câu trả lời của tôi, hãy tìm phần "Cập nhật Trình tạo truy vấn" trong câu trả lời ở trên.
Học viên

Tôi đã thử DB :: bảng ('shop_metas') :: phương thức updateOrCreate nhưng điều này mang lại cho tôi lỗi sau BadMethodCallException trong Macroable.php dòng 59: Phương thức updateOrInsert không tồn tại. Mặc dù tôi sử dụng DB;
Swapnil Shende

17

Lưu chức năng:

$shopOwner->save()

đã làm những gì bạn muốn ...

Mã số rốn

    // 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
Điều đó không giống như một hoạt động upert nguyên tử. Nếu không, điều này có thể gây ra tình trạng chủng tộc.
Emil Vikström

Mã này là để kiểm tra xem mô hình được tải từ DB hay là Mô hình dựa trên bộ nhớ. Cập nhật hoặc Tạo cần định nghĩa rõ ràng về các cột chính cần kiểm tra và không thể được thực hiện hoàn toàn.
AMIB

17

firstOrNewsẽ tạo bản ghi nếu không tồn tại và cập nhật một hàng nếu đã tồn tại. Bạn cũng có thể sử dụng updateOrCreateở đây là ví dụ đầy đủ

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

Nếu có chuyến bay từ Oakland đến San Diego, hãy đặt giá thành 99 đô la. nếu không tồn tại tạo hàng mới

Tài liệu tham khảo tại đây: ( https://laravel.com/docs/5.5/eloquent )


7

Nếu bạn cần chức năng tương tự bằng cách sử dụng DB, trong Laravel, >= 5.5bạn có thể sử dụng:

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

hoặc phiên bản tốc ký khi $attributes$valuesgiống nhau:

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

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

Sau đó thực hiện các thay đổi của bạn và tiết kiệm. Lưu ý FirstOrNew không thực hiện thao tác chèn nếu không tìm thấy, nếu bạn không cần thì đó là FirstOrCreate.


2

Thêm một tùy chọn nếu id của bạn không tự động tăng và bạn biết nên chèn / cập nhật cái nào:

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

2

Giống như phương thức FirstOrCreate, updateOrCreate vẫn duy trì mô hình, do đó không cần phải gọi 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]
);

Và cho vấn đề của bạn

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

1

Trên thực tế FirstOrCreate sẽ không cập nhật trong trường hợp thanh ghi đã tồn tại trong DB. Tôi đã cải thiện một chút giải pháp của Erik vì tôi thực sự cần cập nhật một bảng có các giá trị duy nhất không chỉ cho cột "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);
    }
}

Sau đó, bạn sẽ sử dụng nó như thế này:

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

Điều gì là tốt khi không làm điều này: 1. Xóa dựa trên khóa và 2. tạo với các giá trị mới. Đây vẫn là 2 hoạt động. Là để tiết kiệm thời gian để lập chỉ mục trong trường hợp tạo và xóa?
Hafiz

1

như @JuanchoRamone đã đăng ở trên (cảm ơn @Juancho) nó rất hữu ích cho tôi, nhưng nếu dữ liệu của bạn là mảng, bạn nên sửa đổi một chút như thế này:

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

Chỉ cần lưu ý nhanh rằng đây phải là cập nhật. Tạo ra thay vì tạoOrUpdate
John Shipp

Ok nhưng nếu có 1000 hàng, nó sẽ chạy 1000 truy vấn?
Marcelo Agimóvel


-2

kiểm tra xem người dùng có tồn tại hay không. Nếu không chèn

$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           

Chào mừng bạn đến với SO. Hãy xem cách trả lời này để cung cấp câu trả lời chất lượng. ---
thewaywewere

Vui lòng gắn thẻ khung bạn đang sử dụng, phiên bản php, cơ sở dữ liệu.
Jason Joslin

1
Tôi đang sử dụng Laravel 5.4, php7 và mysql
Sabrina Abid

Sabrina Đây không phải là một giải pháp lý tưởng vì các chức năng đã tồn tại trong laravel để làm như vậy. Nhưng của bạn là một giải pháp chung
djangodude

Phương pháp trường học cũ của nó laravel đã có một chức năng cho việc này. Xem câu trả lời được chọn
Saeed Ansari
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.