
本文深入探讨了Eloquent模型实例的update()方法在更新指定字段时,同时会持久化模型上所有“脏”属性的行为。这一特性源于update()内部调用了save()方法。为了避免意外更新非指定字段,教程提供了使用查询构建器直接进行更新的解决方案,并强调了更新后同步模型实例状态的重要性,旨在帮助开发者更精确地控制数据持久化过程。
Eloquent update() 方法的内部机制
在使用eloquent时,开发者通常会通过模型实例调用update()方法来更新数据库记录。然而,一个常见的误解是,update()方法只会更新作为参数传入的特定字段。实际上,当您通过模型实例调用update()方法时,eloquent的内部实现会首先填充(fill)传入的属性,然后调用模型的save()方法。
查看Eloquent Model.php 的源码,update()方法的定义清晰地揭示了这一点:
/** * Update the model in the database. * * @param array $attributes * @param array $options * @return bool */public function update(array $attributes = [], array $options = []){ if (! $this->exists) { return false; } return $this->fill($attributes)->save($options);}
这意味着,update()方法本质上是fill()和save()方法的组合。而save()方法的作用是持久化模型实例上所有已修改(即“脏”)的属性到数据库。因此,如果在调用update()之前,模型实例上已经有其他属性被修改,这些“脏”属性也会随着update()操作一并被保存。
示例:
考虑以下代码片段:
$user = User::find(1); // 从数据库加载用户$user->is_admin = 1; // 将is_admin属性标记为“脏”$user->update(['first_name' => 'Alex']); // 更新first_name// 此时,数据库中的 is_admin 字段也会被更新为 1
在这个例子中,即使update()方法只指定了更新first_name,但由于在调用update()之前is_admin属性已被修改,update()内部调用的save()方法会将is_admin的更改也一并写入数据库。
避免意外更新“脏”属性的策略
为了避免update()方法意外地持久化模型实例上的所有“脏”属性,当您只想更新特定字段而忽略模型实例上其他已修改的属性时,推荐使用查询构建器(Query Builder)的update()方法。
查询构建器的update()方法直接对数据库执行更新操作,它不涉及Eloquent模型实例的save()生命周期,因此只会更新您明确指定的字段。
解决方案:使用查询构建器进行更新
$user = User::find(1); // 获取模型实例$user->is_admin = 1; // 此时is_admin属性已被修改,但我们不想保存它// 使用查询构建器直接更新数据库User::whereKey($user->getKey())->update(['first_name' => 'Alex']);// 注意:此时 $user 实例的 first_name 属性仍是旧值,is_admin 仍是 1。// 数据库中的 first_name 已更新为 'Alex',is_admin 保持不变。
通过User::whereKey($user->getKey())->update([‘first_name’ => ‘Alex’]);,我们绕过了模型实例的save()方法,确保只有first_name字段被更新。
更新后同步模型实例状态
当您使用查询构建器直接更新数据库时,当前的Eloquent模型实例并不会自动反映这些更改。为了保持模型实例与数据库的同步,您需要手动更新模型实例的属性。
$user = User::find(1);$user->is_admin = 1;// 使用查询构建器更新数据库User::whereKey($user->getKey())->update(['first_name' => 'Alex']);// 手动同步模型实例的属性$user->first_name = 'Alex';// 如果需要将该属性标记为“非脏”并更新原始属性,可以使用 setOriginalAttribute$user->setOriginalAttribute('first_name', 'Alex');
setOriginalAttribute()方法可以将指定属性的“原始值”设置为新值,这有助于在后续操作中正确判断属性是否被修改(即是否为“脏”)。如果只是简单地赋值$user->first_name = ‘Alex’;,那么$user->isDirty(‘first_name’)将为false,但$user->getOriginal(‘first_name’)仍是旧值。使用setOriginalAttribute可以更彻底地同步。
总结与注意事项
Model::update()行为: 通过Eloquent模型实例调用update()方法,会触发fill()和save()操作,因此会持久化模型实例上所有已修改的“脏”属性,而不仅仅是传入update()方法的属性。精确控制更新: 当您只想更新数据库中特定字段,而不想影响模型实例上其他已修改但未打算保存的属性时,应使用查询构建器的where()->update()方法。模型实例同步: 使用查询构建器更新数据库后,请务必手动更新或刷新您的Eloquent模型实例,以确保其状态与数据库保持一致。可以使用$model->refresh()(会进行一次新的数据库查询)或手动设置属性并使用setOriginalAttribute()。syncOriginal()方法: syncOriginal()方法用于将模型当前属性值同步为原始值,有效地清除所有“脏”状态。它可以在save()或update()操作之前使用,以确保只有在syncOriginal()之后发生的修改才会被持久化。但在上述场景中(即update()方法已经调用save()),syncOriginal()在update()之后调用将无法阻止update()保存脏属性,因为它已经完成了保存操作。其主要用途是在保存操作前重置模型状态,或在获取模型后立即清除其初始的“脏”状态。
理解Eloquent update()方法的底层机制,并根据实际需求选择合适的更新策略,是编写健壮、可预测Laravel应用的关键。
以上就是Eloquent update() 方法的行为解析与实践指南的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1266975.html
微信扫一扫
支付宝扫一扫