Grails подключается к GORM перед обновлением()

У меня есть внутреннее требование с вложенными классами предметной области, где я хочу, чтобы обновления родительских отношений распространялись на дочерние элементы. Пример кода может прояснить:

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

Когда оценкаEnd родительской вехи обновляется, я хочу, чтобы дочерняя оценка автоматически обновлялась на ту же сумму. ловушка GORM beforeUpdate() кажется логичным местом для этого:

Чтобы упростить жизнь, я хотел бы использовать простую арифметику дат, поэтому я добавил следующий метод для класса 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 не срабатывает и не делает то, что я хочу. Любые идеи?


person Visionary Software Solutions    schedule 08.05.2011    source источник
comment
Почему бы не использовать сеттер estimatedEnd?   -  person Victor Sergienko    schedule 08.05.2011
comment
Я подозреваю, что события GORM могут не выполняться во время тестов.   -  person Dónal    schedule 09.05.2011
comment
@Victor: Хороший вопрос. Я даже не думал об этом, но это имеет даже больше смысла. @Don: Я полагаю, что они не будут выполняться после модульных тестов, но они работают с полной базой данных в интеграционных тестах.   -  person Visionary Software Solutions    schedule 09.05.2011
comment
Конечно. Это явно доменная логика, а не какая-то инфраструктура постоянства.   -  person Victor Sergienko    schedule 10.05.2011


Ответы (1)


У меня есть решение для вас.

1) Вызовите save(flush:true) при втором вызове сохранения после того, как вы обновите оценочный конец вехи1. Это приведет к немедленному запуску функции beforeUpdate().

2) Даже после того, как вы сделаете № 1, ваше утверждение будет продолжать давать сбой, потому что вы сравниваете 2 немного разные даты (вы используете отдельный объект Date в каждом конструкторе Milestone, поэтому 2-я дата немного позже/больше, чем первая.) Если вы использовали тот же экземпляр даты, например

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

тогда утверждение будет успешным. Я оставлю вам, что делать дальше с точки зрения наилучшего способа сравнения немного разных дат, но вам, возможно, придется мириться с разницей в точности порядка миллисекунд.

Надеюсь, это поможет,

Иордания

person Jordan H.    schedule 08.05.2011
comment
Это было именно так. Хороший спектакль, старина! У меня было предчувствие сбросить сохранение, но арифметика даты была тонкой. Спасибо за помощь! - person Visionary Software Solutions; 09.05.2011