【问题标题】:Grails hook into GORM beforeUpdate()Grails 挂钩到 GORM beforeUpdate()
【发布时间】:2011-08-21 00:20:24
【问题描述】:

我对嵌套域类有一个内部要求,我希望将父关系的更新传播给子级。一个代码示例可能会清楚:

class Milestone {
    static belongsTo = [project:Project]
    static hasMany = [goals:OrgGoals, children:Milestone]
    String name
    Date start
    Date estimatedEnd
    Date achievedEnd
    ...
}

当父里程碑的估计结束更新时,我希望子里程碑的估计自动更新相同的数量。 GORM's beforeUpdate() hook 似乎是一个合乎逻辑的地方:

为了让生活更轻松,我想使用一些simple Date arithmetic,所以我在 Milestone 类中添加了以下方法:

def beforeUpdate()
    {
        // check if an actual change has been made and the estimated end has been changed
        if(this.isDirty() && this.getDirtyPropertyNames().contains("estimatedEnd"))
        {
            updateChildEstimates(this.estimatedEnd,this.getPersistentValue("estimatedEnd"))
        }
    }

private void updateChildEstimates(Date newEstimate, Date original)
    {
        def difference = newEstimate - original
        if(difference > 0)
        {
            children.each{ it.estimatedEnd+= difference }
        }
    }

没有编译错误。但是当我运行以下集成测试时:

void testCascadingUpdate() {
        def milestone1 = new Milestone(name:'test Parent milestone',
            estimatedEnd: new Date()+ 10,
        )
        def milestone2 = new Milestone(name:'test child milestone',
            estimatedEnd: new Date()+ 20,
        )
        milestone1.addToChildren(milestone2)
        milestone1.save()
        milestone1.estimatedEnd += 10
        milestone1.save()
        assert milestone1.estimatedEnd != milestone2.estimatedEnd
        assert milestone2.estimatedEnd == (milestone1.estimatedEnd + 10)
    }

我明白了:

Unit Test Results.

    Designed for use with JUnit and Ant.
All Failures
Class   Name    Status  Type    Time(s)
MilestoneIntegrationTests   testCascadingUpdate Failure Assertion failed: assert milestone2.estimatedEnd == (milestone1.estimatedEnd + 10) | | | | | | | | | | | Mon Jun 06 22:11:19 MST 2011 | | | | Fri May 27 22:11:19 MST 2011 | | | test Parent milestone | | false | Fri May 27 22:11:19 MST 2011 test child milestone

junit.framework.AssertionFailedError: Assertion failed: 

assert milestone2.estimatedEnd == (milestone1.estimatedEnd + 10)
       |          |            |   |          |            |

       |          |            |   |          |            Mon Jun 06 22:11:19 MST 2011
       |          |            |   |          Fri May 27 22:11:19 MST 2011
       |          |            |   test Parent milestone

       |          |            false
       |          Fri May 27 22:11:19 MST 2011
       test child milestone

    at testCascadingUpdate(MilestoneIntegrationTests.groovy:43)

    0.295

这表明 beforeUpdate 没有触发并做我想做的事。有什么想法吗?

【问题讨论】:

  • 为什么不使用estimatedEnd setter?
  • 我怀疑 GORM 事件可能不会在测试期间执行
  • @Victor:好点。我什至没有想到这一点,但这更有意义。 @Don:我相信它们不会在单元测试之后执行,但它们会在集成测试中针对完整的数据库运行。
  • 当然。这显然是一个领域逻辑,而不是一些持久性基础设施。

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


【解决方案1】:

我有一个解决方案。

1) 在更新里程碑 1 的估计结束后,在第二次保存调用时调用 save(flush:true)。这将强制 beforeUpdate() 立即触发。

2) 即使在执行 #1 之后,您的断言仍将继续失败,因为您正在比较 2 个稍微不同的日期(您在每个 Milestone 构造函数中使用单独的 Date 对象,因此第二个日期比第一个日期稍晚/更大.) 如果您使用相同的日期实例,例如

Date date = new Date() 
def milestone1 = new Milestone(name:'test Parent milestone',
            estimatedEnd: date + 10)
def milestone2 = new Milestone(name:'test child milestone',
            estimatedEnd: date + 20,
        )

那么断言就会成功。关于比较略有不同日期的最佳方法,我将留给您下一步该做什么,但您可能不得不容忍毫秒级的精度差异。

希望对你有帮助,

约旦

【讨论】:

  • 就是这样。好剧,老铁!我对刷新保存有一种感觉,但日期算术的东西很微妙。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2014-08-03
  • 1970-01-01
  • 1970-01-01
  • 2020-02-06
  • 1970-01-01
  • 2012-03-06
  • 2010-12-29
  • 1970-01-01
相关资源
最近更新 更多