Обновление Laravel Eloquent, если были внесены изменения


86

Есть ли способ обновить запись в Laravel, используя красноречивые модели, только если в эту запись было внесено изменение? Я не хочу, чтобы какой-либо пользователь снова и снова запрашивал базу данных без уважительной причины, просто нажимая кнопку, чтобы сохранить изменения. У меня есть javascriptфункция, которая включает и отключает кнопку сохранения в зависимости от того, изменилось ли что-то на странице, но я хотел бы знать, можно ли сделать такую ​​функцию и на стороне сервера. Я знаю, что могу сделать это сам (то есть: не обращаясь к внутренней функциональности фреймворка), просто проверив, есть ли изменения в записи, но прежде чем делать это таким образом, я хотел бы знать, заботится ли уже о красноречивой модели Laravel это, поэтому мне не нужно заново изобретать колесо.

Вот как я использую для обновления записи:

$product = Product::find($data["id"]);
$product->title = $data["title"];
$product->description = $data["description"];
$product->price = $data["price"];
//etc (string values were previously sanitized for xss attacks)
$product->save();

3
Почему бы не включить ведение журнала базы данных, а затем проверить журналы, чтобы увидеть, какой запрос Eloquent на самом деле выполняет при сохранении: вы можете быть приятно удивлены
Марк Бейкер

4
Обратите внимание, что модели Laravel содержат dirtyфлаг, который используется для определения, действительно ли требуется обновление базы данных, и этот флаг устанавливается путем сравнения исходных findзначений столбцов со значениями в точке, где вы выполняете сохранение
Марк Бейкер,

@MarkBaker Отличный совет!
user2755140 04

Ответы:


177

Вы уже это делаете!

save()проверит, изменилось ли что-нибудь в модели. Если это не так, он не будет запускать запрос к базе данных.

Вот соответствующая часть кода Illuminate\Database\Eloquent\Model@performUpdate:

protected function performUpdate(Builder $query, array $options = [])
{
    $dirty = $this->getDirty();

    if (count($dirty) > 0)
    {
        // runs update query
    }

    return true;
}

getDirty()Метод просто сравнивает текущие атрибуты с копией , сохраненной в originalмомент создания модели. Это делается в syncOriginal()методе:

public function __construct(array $attributes = array())
{
    $this->bootIfNotBooted();

    $this->syncOriginal();

    $this->fill($attributes);
}

public function syncOriginal()
{
    $this->original = $this->attributes;

    return $this;
}

Если вы хотите проверить, не загрязнена ли модель, просто позвоните isDirty():

if($product->isDirty()){
    // changes have been made
}

Или, если вы хотите проверить определенный атрибут:

if($product->isDirty('price')){
    // price has changed
}

Замечательно. Спасибо. Интересно теперь, как я могу получить доступ к этому грязному флагу, чтобы узнать, была ли предпринята попытка обновления без каких-либо изменений? Я имею в виду: отдача от этого действия?
user2755140 04

1
@DaseinA Вы можете использовать isDirty()для этого. См. Обновленный ответ
lukasgeiter

2
Тем, кто читает это, обязательно ознакомьтесь с этим ответом перед использованием isDirty().
Alex

1
Есть getChanges()метод. Проверьте мой ответ stackoverflow.com/a/54132163/1090395
Младен Джанжетович

FYI isDirty()будет, trueесли вы не укажете свои атрибуты правильно. У меня было число с плавающей запятой, которое было точно таким же, как в базе данных, однако, поскольку я устанавливал число с плавающей запятой со строкой (например, «10,50» вместо 10,50), он обнаруживал бы его как изменение и выполнял обновление.
Maarten de Graaf,


11

Мне нравится добавлять этот метод, если вы используете форму редактирования, вы можете использовать этот код для сохранения изменений в вашей update(Request $request, $id)функции:

$post = Post::find($id);    
$post->fill($request->input())->save();

имейте в виду, что вы должны называть свои поля ввода одним и тем же именем столбца. fill()Функция будет делать всю работу за вас :)


3
На самом деле это ответ, который я искал, я забыл об имени fillи о том , как массово передать ему запрос. Благодарность! Мне не нужно было передавать идентификатор, так как я обновляю, так что он уже там $request->id.
blamb
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.