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

更新;“最新更新”;Grails中父域类中的字段,grails,gorm,grails-domain-class,Grails,Gorm,Grails Domain Class,我有一个父域类,该类有另一个域类的hasMany。父域类和子域类都有lastUpdated和dateCreated字段。我的问题是,当我更新子域类时,我需要父域类反映该更改并更新其lastUpdated字段 Grails提供的父级和子级之间是否存在实现此功能的映射或其他配置 更新 我向子域类添加了以下行: def beforeUpdate = { parent.lastUpdated = new Date() } 我还必须确保在控制器中,当我更新一个子项时,我还必须保存父项以保留新的l

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

Grails提供的父级和子级之间是否存在实现此功能的映射或其他配置

更新

我向子域类添加了以下行:

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

我还必须确保在控制器中,当我更新一个子项时,我还必须保存父项以保留新的
lastUpdated
字段。这似乎很好,但我仍然想知道是否有映射或类似的东西可以做到这一点。

我感觉您建议的实现将有缺陷。您通过手动设置
lastUpdated
日期来更新
parent
,这可能会导致grails在对其执行脏检查后再次更新
lastUpdated
。如果是这样的话,你最终会得到一个上次更新的时间,它发生在你最初设定的日期之后。在您的测试中,这可能只有几(毫秒)秒,但您不能保证这一点

不仅如此,您的实现更难维护,因为您增加了父级和子级的耦合

我可以建议另一种实现方式吗?lastUpdated字段应该表示特定域对象的更新时间。你要找的日期不完全一样,所以我不会试图以“错误”的方式使用现有的约定。听起来您希望父对象的日期是“上次修改子对象的时间”

改用公式。

要做到这一点,你可以使用一个。通过一个公式,您无需直接修改父对象即可获得所需的内容,并且您仍然可以使用动态查找器和其他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都会在中加载公式的值。现在,无论何时保存一个子项,父项都将拥有该属性的准确值,而不必接触父项。

在我的一个项目中,域是这样的。 一个程序有很多AdvertisingMaterial,我们有AdvertisingMaterial、FlashAd、ImageAd等子类。用户希望能够过滤包含flashAds、imageAds等的程序。现在我需要根据数据库表中的类属性进行过滤(当tablePerHierarchy为true时)。所以我在我的域类中做了一些更改来获得这个属性

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)"
}
ListadMaterials=advisingmaterial.findAllByClassName(“com.project.FlashAd”)
静态映射={
全名公式:“CONCAT(名字、姓氏)”
totalAmount公式:“总和(金额)”
}

我用了一个黑客。我在我的父类域类中添加了一个
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_instance.save() // save the child
child_instance.parent.touch().save() // updates parent's time stamp

这将增加
updateTrigger
值,
save()
将自动更新
lastUpdated
字段,这得益于映射中将
autoTimestamp
设置为
true
updatedTrigger
被设置为可空,这样它就不会使任何现有数据库表无效,因此可以随时添加到任何域类。

“我还必须确保在控制器中,当我更新子级时,我还必须保存父级”。使用Grails 2.2.0,beforeUpdate技术可以工作。不需要保存父级,也不会出现任何双重保存行为。所以你不需要任何公式,只需要听众。他真的有效吗?我以前没有试过,或者我在任何地方见过这种类型的东西了。。。!!!对不起,我给了你一个否决票:建议OP的解决方案有效,而你的感觉是错误的。这个公式带来了很多新的变化:孩子们也有时间戳,如果你的父实体没有被刷新和再次查询,这个公式可能不会被调用……我认为这里的观点是正确的。您不应该真正修改lastUpdated的实现,因为您不知道它还依赖于什么。我认为这最终是一个优雅的解决方案。但是,我认为代码示例中有一个错误,我现在将更新它。这个例子并不是像用户Guillaume建议的那样存储一个额外的列,该列只是您访问公式值的方式。@Guillaume,也许“感觉”不是这里最好使用的词。我得到的是Daniel Bower的建议——这种更新方式现在可能有效,但你打破了Grails设定的惯例,这意味着它在未来可能不起作用。我同意使用您指出的公式的缺点,但这些问题取决于实现,而不是框架。