更新 Grails 中父域类中的“lastUpdated”字段
Posted
技术标签:
【中文标题】更新 Grails 中父域类中的“lastUpdated”字段【英文标题】:Update "lastUpdated" Field in Parent Domain Class in Grails 【发布时间】:2012-06-28 00:13:00 【问题描述】:我有一个父域类,它有另一个域类的hasMany
。父域类和子域类都有lastUpdated
和dateCreated
字段。我的问题是,当我更新子域类时,我需要父域类来反映该更改并更新其 lastUpdated
字段。
Grails 提供的父子节点之间是否有任何映射或其他配置可以实现此功能?
更新
我在子域类中添加了以下几行:
def beforeUpdate =
parent.lastUpdated = new Date()
我还必须确保在控制器中更新孩子时,我还必须保存父级以保持新的lastUpdated
字段。这似乎工作正常,但我仍然想知道是否有映射或类似的东西可以做到这一点。
【问题讨论】:
“我还必须确保在控制器中,当我更新一个孩子时,我还必须保存父母” 在 Grails 2.2.0 中,beforeUpdate 技术有效。没有必要保存父母,您不会有任何双重保存行为。所以你不需要任何公式,只需要监听器。 【参考方案1】:我感觉你建议的实现会有问题。您正在通过手动设置lastUpdated
日期来更新parent
,这可能会导致grails 在对其进行脏检查后再次更新lastUpdated
。如果是这种情况,您实际上会得到一个 lastUpdated 时间,该时间发生在您最初设置的日期之后。在您的测试中,这可能只有几(毫秒)秒,但您不能保证。
不仅如此,由于增加了 Parent 和 Child 的耦合,您的实现更难维护。
我可以建议另一种实现方式吗? lastUpdated 字段应该代表特定域对象的更新时间。您要查找的日期并不完全相同,因此我不会尝试以“错误”的方式使用现有约定。听起来您希望父对象的日期是“最后一次修改子对象”。
改用公式。
为此,您可以使用formula。使用公式,您无需直接修改父对象即可得到您想要的结果,并且您仍然可以使用动态查找器和其他 Grails 糖。
class Parent
...
Date lastChildUpdated
static hasMany = [ children: Child ]
static mapping =
...
lastChildUpdated formula: '(SELECT max(c.last_updated) FROM child c WHERE c.parent_id = id)'
每当您从数据库中读取对象时,GORM 都会加载公式的值。现在,无论何时您保存子项,父项都将获得该属性的准确值,而无需触摸父项。
【讨论】:
他真的有用吗?,我之前没有尝试过,也没有在任何地方看到过这种类型的东西......!!! 对不起,我给了你一个downvote:建议OP的解决方案工作,你的感觉是错误的。而且这个公式带来了很多新的变化:孩子的时间戳,如果你的父实体没有被刷新和再次查询,这个公式可能不会被调用...... 我认为这里的观点是正确的。您不应该真正修改 lastUpdated 的实现,因为您真的不知道还有什么可能依赖于它。我认为这最终是一个优雅的解决方案。但是,我认为代码示例中存在错误,我现在将其更新。该示例没有像用户 Guillaume 建议的那样存储额外的列,该列只是您访问公式值的方式。 @Guillaume,也许“感觉”不是在这里使用的最佳词。我得到的是 Daniel Bower 的建议——更新这种方式现在可能有效,但你打破了 Grails 设定的约定,这意味着它在未来可能不起作用。我同意使用您指出的公式的缺点,但这些问题取决于实现,而不是框架。【参考方案2】:我使用了一个 hack。我在我的 parent 域类中添加了一个 Long updateTrigger
字段和一个 touch
方法:
class Parent
Long updateTrigger
static mapping =
autoTimestamp true
static constraints =
updateTrigger(nullable:true)
public touch()
if (updateTrigger == null) updateTrigger = 0
updateTrigger++
this
在 child 控制器的更新/保存操作中,我只是调用:
child_instance.save() // save the child
child_instance.parent.touch().save() // updates parent's time stamp
这将增加updateTrigger
的值,并且save()
将自动更新lastUpdated
字段,这要归功于映射中的autoTimestamp
设置为true
。 updatedTrigger
设置为可为空,这样它就不会使任何现有的数据库表无效,因此可以随时添加到任何域类中。
【讨论】:
【参考方案3】:在我的一个项目中,该域是这样的。 一个程序有很多 AdvertisingMaterial,我们有 AdvertisingMaterial、FlashAd、ImageAd 等的子类。用户希望能够过滤具有 flashAds、imageAds 等的程序。现在我需要根据我们拥有的类属性进行过滤在数据库表中(当表 tablePerHierarchy 为真时)。所以我在我的域类中做了一些改变来获得这个属性。
class AdvertisingMaterial
String className
static constraints =
className(nullable: true)
static mapping =
className formula: 'CLASS'
现在我也可以在我的动态查找器和条件查询中使用这个 className 字段。所以我可以做类似的事情
List<AdvertisingMaterial>adMaterials=AdvertisingMaterial.findAllByClassName("com.project.FlashAd")
static mapping =
fullName formula: "CONCAT(FIRST_NAME,' ',LAST_NAME)"
totalAmount formula: "SUM(AMOUNT)"
【讨论】:
以上是关于更新 Grails 中父域类中的“lastUpdated”字段的主要内容,如果未能解决你的问题,请参考以下文章