我有一个Note
域类,当保存新笔记时,我需要为其创建一个NoteEvent
,为后代录制已创建笔记的内容。 Note
有一个NoteEvents
的集合,每个NoteEvent
都会跟踪它所属的Note
。
Note
类:
class Note {
String noteText
Date dateCreated
static hasMany = [events : NoteEvent]
}
NoteEvent
类:
class NoteEvent {
Date dateCreated
String type
static belongsTo = [note : Note]
}
要在创建便笺时处理新NoteEvents
的保存,我使用的是afterInsert
,因为我正在整个地方保存便笺实例(这会重复且耗时。在每次保存新笔记后都有特定的事件创建代码),beforeInsert
显然没有处理Note
的持久化实例 - NoteEvent
没有任何内容可供note
作为Note
。
所以现在我的class Note {
String noteText
Date dateCreated
static hasMany = [events : NoteEvent]
def afterInsert = {
def event = new NoteEvent(type: "CREATED")
addToEvents(event)
save()
}
}
课程是:
NoteEvent
但是当我更新其中一个笔记时,我还需要创建一个NoteEvent
,这就是混乱和沮丧以及严重缺乏咖啡的地方。附加一个新的“更新的”{{1}在更新时的一个注释中,我出色地决定再次使用afterUpdate
,以避免在需要更新Note
实例时将事件创建代码洒在应用程序的所有位置。
现在,对于Note
,我有:
class Note {
String noteText
Date dateCreated
static hasMany = [events : NoteEvent]
def afterInsert = {
def event = new NoteEvent(type: "CREATED")
addToEvents(event)
save()
}
def afterUpdate = {
def event = new NoteEvent(type: "UPDATED")
addToEvents(event)
save()
}
}
要在笔记集合中添加新事件,我使用动态addTo()
方法,然后需要save()
个实例。但是在“之后”事件的情况下,这是对save()
的第二次调用。因此,当我第一次保存新实例并调用afterInsert
时,刚刚保存的实例会立即再次保存,这会导致afterUpdate
事件被触发,现在我有两个音符事件:从我刚刚保存笔记时“创建”一个,并且从“创建”笔记中“更新”一个导致笔记再次保存。
我不清楚如何使用“之前”事件可以帮助解决这种情况。我怎么能这样做?
答案 0 :(得分:4)
您实际上可以使用beforeInsert
和beforeUpdate
方法。这是因为addTo*
方法不需要Note
作为持久化实例。
NoteEvent
会在保存Note
时保存,因为在NoteEvent
方法中保存Note
之前添加了beforeUpdate
。请查看addTo*
docs以获得更长的解释。
我能够获得以下两个Note
课程来完成我相信你想要的课程。我确实遇到了一个问题,即更新Note
时会添加两个NoteEvent
个对象。我能够通过确保控制器的更新方法使用noteInstance.save()
而不是noteInstance.save(flush:true)
来解决此问题。
class Note {
String noteText
Date dateCreated
static hasMany = [events : NoteEvent]
def beforeInsert = {
def event = new NoteEvent(type: "CREATED")
addToEvents(event)
}
def beforeUpdate = {
def event = new NoteEvent(type: "UPDATED")
addToEvents(event)
}
}
如果你想要一个更精简的版本,addTo*
方法知道添加了什么类型的对象,你可以使用Map
的{{1}}构造函数
NoteEvent
答案 1 :(得分:3)
可能有一种方法可以使用beforeInsert
和beforeUpdate
,因为这些不需要保存Note
实例。像这样进行二次更新/插入的典型方法是使用withNewSession
,但在这种情况下,我不确定它是否有意义,因为这更像是创建一个独立的对象,而你需要重新加载新会话中的Note
。不是那么糟糕,但没有表现。
执行此操作的一种方法是删除集合并直接保存NoteEvent
个实例:
class Note {
String noteText
Date dateCreated
Set<NoteEvent> getEvents() {
NoteEvent.findAllByNote(this)
}
def afterInsert() {
new NoteEvent(type: "CREATED", note: this).save()
}
def afterUpdate() {
new NoteEvent(type: "UPDATED", note: this).save()
}
}
class NoteEvent {
Date dateCreated
String type
Note note
}
您丢失了级联,因此您希望删除事务服务方法中的Note
实例,以便删除其关联的NoteEvent
。但这确实是整个问题的解决方案。只需删除afterInsert
和afterUpdate
回调,并在事务服务方法中完成所有工作(创建,更新和删除)。每当您执行多个数据库更新时,您应该以事务方式执行它们,以便它们都成功或全部失败。这也符合您的反杂乱要求,因为所有工作都封装在服务中。
答案 2 :(得分:2)
“因为我正在整个地方保存笔记实例”
我可以问你在哪里拯救他们吗?我会避免在您的控制器中保存您的域实例。如果你将它们全部保存在那里,那么可能值得一看整体设计。
就个人而言,我倾向于创建某种NoteService,如果可能的话我会集中CRUD操作。示例服务将是:
class NoteService
{
Note create (String noteText)
{
Note note = new Note(noteText: noteText)
.addToEvents(new NoteEvent(type: NoteEvent.CREATED))
.save()
}
Note update (int id, String noteText)
{
Note note = Note.findById(id)
note.setNoteText(noteText)
note.addToEvents(new NoteEvent(type: NoteEvent.UPDATED))
.save()
}
....
}
我更喜欢上述方法的原因是,如果您发现自己希望在响应这些事件时做更多事情并避免重复代码,那么它会更好地扩展。
另一种方法可能是登录过滤器。但是,如果要在许多地方保存笔记实例,这可能会很棘手/混乱。
否则我会考虑使用上面提到的beforeInsert / beforeUpdate函数。