更新 Grails 中父域类中的“lastUpdated”字段

Posted

技术标签:

【中文标题】更新 Grails 中父域类中的“lastUpdated”字段【英文标题】:Update "lastUpdated" Field in Parent Domain Class in Grails 【发布时间】:2012-06-28 00:13:00 【问题描述】:

我有一个父域类,它有另一个域类的hasMany。父域类和子域类都有lastUpdateddateCreated 字段。我的问题是,当我更新子域类时,我需要父域类来反映该更改并更新其 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 设置为trueupdatedTrigger 设置为可为空,这样它就不会使任何现有的数据库表无效,因此可以随时添加到任何域类中。

【讨论】:

【参考方案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”字段的主要内容,如果未能解决你的问题,请参考以下文章

Grails,Field 的域类默认值

在另一个域类中查看 grails 域类属性

在域类中使用 grails 服务

如何在 Grails 域类中正确设置属性值

Grails Scaffolding Templates - 从域类中获取属性

如何在 Grails 2.2 中设置域类值的默认值?