Replies: 2 comments 1 reply
-
An update is still an update. If you call update it means you want to update. The fact that you are updating only your updated_at because the rest of the data is the same is a corner case which you could handle by not calling updateOrCreate. It could be a breaking change if others are depending on this. |
Beta Was this translation helpful? Give feedback.
-
To make it clear, I'm not updating only I am checking the documentation since I clearly recall that if no attributes have been changed, it won't update the Will re-create the scenarios when I have more time and get back to this one. I still think there's something not correct, but want to be sure if it's with my understanding of the framework or with my code. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Before I file a bug report, wanted to discuss if I found it in the Laravel Framework.
It all started when I was using ActivityLog, which created a lot of "ghost" entries. I call those where the update is being done to the model and it's being logged, but nothing is changed. After I debugged a lot, this is what I have found.
I have a model and related model which uses
updating
andupdated
events. For this case,updating
is important. When a related model is saved, the updating event causes some processing and it changes the model that's being saved. Basically, when the data comes in, it's different than the one already in the database but then the updating event changes it to match the one already saved in database (we have a business model that works like this). But this causes theisDirty
to be true and it triggers the save event, which then updatesupdated_at
and ActivityLog creates new entry.Why do I think it's a bug? Because the
updating
event is triggered too late or when actually saving a model, the dirtiness is checked too late. This is the flow of the current code.$model->relatedModel()->updateOrCreate(['id' => 1], $attributes)
which is located inlaravel\framework\src\Illuminate\Database\Eloquent\Relations\HasOneOrMany.php:L268
$instance->save()
on line 273, which is located inlaravel\framework\Illuminate\Database\Eloquent\Model.php:L1113
$this->performUpdate($query)
on line 1131, which is then located in same file at line 1192performUpdate(Builder $query)
then fires the updating event, updates the timestamps and checks if the model is dirty again. Because ofupdating
event here, the model's attributes were set to the same as they were already in the database, but because of the timestamp check, model is now dirty and it saves itThe current
performUpdate(Builder $query)
looks like this:But I think it should look like this:
The updated function sets timestamps ONLY if it finds dirty attributes and not before. This way the update happens only if the model, changed by
updating
event, is actually still dirty and needs to be updated in the database.To be fair, I haven't tested this in clean installation, but I never change the vendor files, so I assume it will work the same there. I also assume to be sure, I do need to provide more code so that this potential bug can quickly be checked. But before I do that, what do you guys think about this? I understand why the
updating
event is triggered inperformUpdate
function and that it needs to stay there, but why create timestamps before checking the dirtiness of the model again? Isn't it logical that if we do so, that the model will always be dirty?Beta Was this translation helpful? Give feedback.
All reactions