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

我有一个父域类,它有另一个域类的hasMany。父域类和子域类都有lastUpdateddateCreated 字段。我的问题是,当我更新子域类时,我需要父域类来反映该更改并更新其 lastUpdated 字段。

Grails 提供的父子节点之间是否有任何映射或其他配置可以实现此功能?

更新

我在子域类中添加了以下几行:

def beforeUpdate = {
    parent.lastUpdated = new Date()
}

我还必须确保在控制器中更新孩子时,我还必须保存父级以保持新的lastUpdated 字段。这似乎工作正常,但我仍然想知道是否有映射或类似的东西可以做到这一点。

【问题讨论】:

  • “我还必须确保在控制器中,当我更新一个孩子时,我还必须保存父母”
  • 在 Grails 2.2.0 中,beforeUpdate 技术有效。没有必要保存父母,您不会有任何双重保存行为。所以你不需要任何公式,只需要监听器。

标签: grails grails-orm grails-domain-class


【解决方案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)"
    }
    

    【讨论】:

      猜你喜欢
      • 2012-02-21
      • 1970-01-01
      • 2014-08-08
      • 1970-01-01
      • 2012-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多