2011-05-08 2 views
1

부모 관계에 대한 업데이트를 하위 항목에 전파하려는 중첩 도메인 클래스가 필요한 내부 요구 사항이 있습니다. 코드 예제는 명확하게 할 수있다 : 부모 이정표의 estimatedEnd가 업데이트되면Grails는 GORM에 후크를 끼 웁니다. beforeUpdate()

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을 사용하고 싶습니다, 인생을 더 쉽게 만드는을, 그래서 마일스톤 클래스에 다음과 같은 방법을 추가했습니다 :

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) 
    } 

를 내가 얻을 :

beforeUpdate가 발사와 내가 원하는 일을하지 않는 것을 제안
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 

. 어떤 아이디어?

+0

'estimatedEnd' 세터를 사용하지 않는 이유는 무엇입니까? –

+0

테스트 중에 GORM 이벤트가 실행되지 않을 수도 있습니다. –

+0

@ 빅터 : 좋은 지적입니다. 나는 그것에 대해서 생각조차하지 않았지만 그것은 훨씬 더 의미가 있습니다. @Don : Unit 테스트 후 실행되지 않을 것이라고 나는 믿지만 통합 테스트에서 전체 데이터베이스에 대해 실행됩니다. –

답변

5

나는 해결책이 있습니다.

1) 마일스톤 1의 estimatedEnd를 업데이트 한 후 두 번째 저장 호출에서 save (플러시 : true)를 호출합니다. 그러면 beforeUpdate()가 즉시 실행됩니다.

2) 약간의 다른 2 개의 날짜를 비교하기 때문에 # 1을 수행 한 후에도 어설 션이 계속 실패합니다 (각 마일스톤 생성자 내에서 별도의 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, 
     ) 

그러면 어설 션이 성공합니다. 약간 다른 날짜를 비교하는 가장 좋은 방법에 관해서는 다음에해야할 일을 남겨 두겠지만 밀리 초 단위의 정밀도 차이를 허용해야 할 수도 있습니다. 도움이

희망,

요르단

+0

정확히 그랬습니다. 좋은 쇼, 오래된 갈라진 금! 나는 저축을 내뿜는 것에 대한 느낌이 들었지만, 산수 계산은 미묘했습니다. 도와 주셔서 감사합니다! –