【发布时间】:2015-03-03 10:31:36
【问题描述】:
有没有办法在 beforeCommit 回调中确定域实例是否是新的?
上下文:一个 grails 应用程序 (v. 2.2.1),它在下面使用 spring 和 hibernate。
用例: 每当给定类型(父级)或其子级的实例“以显着方式”发生变化时,我们需要向外部系统发送消息,例如Parent 属性发生变化,Parent 获得“已批准”的新孩子等。在同一事务中可能有许多事件会触发 Parent 的消息,我们只需要发送 一个每个父母,每个事务的消息。
我们实现 spring TransactionSynchronization 以在 beforeCommit 中获得通知。我们得到“persistenceContext”,我们检查新实体或脏实体,然后聚合每个父级并在适当时发送通知。相关代码sn-p:
@Override
void beforeCommit(boolean readOnly) {
def transactionObjects = ApplicationContextHolder.applicationContext.sessionFactory.currentSession.transaction.transactionContext.persistenceContext.
List<Object> changedObjects = transactionObjects.findAll {
it.key.isDirty() || isNewInstance(it)
}.collect { it.key }
// do stuff here
}
但是,我们无法找到一种内置方法来确定实例是否为新实例。 isDirty 仅适用于更新。 我们尝试使用 EntityEntry.previousStatus,我们认为它只会对新实例为 null,但测试表明同一对象可以在随后的两次 beforeCommit 调用中具有 previousStatus = null(因此这对我们的目的没有用)。
对我们有用的 hack:
将瞬态布尔值添加到域类 (isNewInstance)
在“beforeInsert”事件中设置为真
并在 beforeCommit 结束时将其清除
但是真的没有内置的休眠 API 可用吗? (我们不能使用 instance.id == null,因为它是在调用 save() 之后,并且 id 将设置在持久但尚未提交的对象中)。
编辑:
假设:Hibernate 最终必须根据实例是否为新实例发出不同的 SQL(插入与更新)。我知道它会根据是否有 ID 生成 SQL,然后将其立即放在事务中,因此不能将空 ID 用作指示符。
问题: 但是hibernate是否不会在内部某个地方保存这些信息,如果是这样,它不提供公共API吗?
【问题讨论】:
-
使用 afterInsert() 方法还不够吗?
-
如果我们使用 afterInsert/Update/Delete,我们 (1) 将其紧密到 gorm (2) 将在子域类和父域类中调用 (3) 每次更改都会触发一个事件对象树例如父级更改及其两个子级将导致 3 个事件,我们应该只发送一个。
标签: java spring hibernate grails