可以将域类配置为在保存时插入新记录而不是更新吗?

Posted

技术标签:

【中文标题】可以将域类配置为在保存时插入新记录而不是更新吗?【英文标题】:Can domain classes be configured to insert a new record instead of updating when saved? 【发布时间】:2010-08-24 22:01:54 【问题描述】:

当我更改域对象时,而不是更新数据库记录,我想存档旧记录并创建一个新记录。我想强制 GORM 自动执行此操作。

例如,如果我有这个域类:

class User 
    String username
    String email
    Boolean active

那我愿意

user.email = email
user.save()

将用户的活动标志设置为 false,保留旧电子邮件的记录。将插入具有新电子邮件地址和 active = true 的新记录。

这是一种常见的模式吗?在域类中是否容易做到,以便透明地发生?

【问题讨论】:

【参考方案1】:

您可以在用户域类中使用 GORM 事件 beforeUpdate(请参阅文档 here 和 here),如下所示应该可以工作(未经测试):

def beforeUpdate() 
  if (isDirty('email')  //enters only if email was changed. Works only with Grails 1.3.x
  User.withNewSession 
    //Create the new entry
    new User(username:username, email:email).save()
    //Update the old entry with the old email value
    email = getPersistentValue('email')
  
  

【讨论】:

有趣,我没想到。但是如何获得新插入的用户(以替换旧实例)? 如果我在新会话中创建新用户,它将在另一个事务中,不是吗?理想情况下,如果出现故障,我希望它与事务的其余部分一起回滚。 @ataylor 是的,这是另一笔交易。只需检查 save() 的返回值并将错误传播到另一个事务以回滚@Pascal 我现在想到的唯一方法是:User.findByEmail(new_email),或将新用户 ID 存储在会话等范围内或闪光【参考方案2】:

我能想到的一个选择是实现soft delete,然后保留一个新用户。我意识到这不是您所要求的,但我不知道如何通过一次保存来做到这一点。不理想的海事组织。

另一种(可能更好)的方法是使用Hibernate Envers 来“版本化”User 实体并保留更改历史记录。我不知道 Envers with Grails 的确切状态,但看起来有一个 plugin 。另见[grails-user] GORM & Envers / Audit History Tables。

【讨论】:

这也是一个很好的全局解决方案。你曾经用 Grails 尝试过 Envers 吗? @fabien7474:不,从来没有。老实说,我不知道 Envers with Grails 的当前状态是什么(实际上我并没有真正做 Grails)。

以上是关于可以将域类配置为在保存时插入新记录而不是更新吗?的主要内容,如果未能解决你的问题,请参考以下文章

更改连接表中的属性值时,Rails 5 正在插入而不是更新

将域转换为 JSON 时缺少版本属性

Grails 更新而不是删除

DTO:最佳实践

TypeORM 在批量保存时抛出重复错误,而不是忽略或更新现有值

在 Grails 中存储和编辑键/值对?