2016-11-24 4 views
0

У нас запуталась странная проблема, когда объекты создаются в первом запросе, но они не возвращаются во втором запросе. Давайте предположим, что у нас есть два класса домена:afterUpdate event hook, транзакции и старое состояние в последовательных запросах

Class A { 
    static hasMany = [bs: B] 

    def afterUpdate() { 
     this.addToBs(new B(a: this)) 
     this.save() 
    } 
} 

Class B { 
    static belongsTo = [a: A] 
} 

Когда путы отправляются на экземпляре А через PUT /as/<id>, update() вызывается в RestfulController, который с аннотацией @Transactional.

Что мы можем наблюдать, так это то, что каждый раз после запроса ответа на запрос API отправителя после ответа на первый запрос GET /bs не возвращает новый экземпляр B, который должен был быть создан в первом запросе и также возвращается по дальнейшим запросам.

Я ожидал, что grails только отправит ответ потребителю API после совершения транзакции, что означает, что следующий запрос должен увидеть все изменения из этой транзакции, не так ли?

Что может быть причиной такого поведения? Выполняется ли транзакция после того, как приложение grails уже отправило ответ потребителю API? Если да, то почему @Transactional вокруг update(), который включен по умолчанию?

Я знаю, что в этом примере код в afterUpdate может также быть помещен в beforeUpdate, но я просто попытался упростить пример, насколько мог.

ответ

0

По моему опыту, код в afterUpdate() и т.п. не включены в транзакцию. Вам нужно будет создать транзакцию явно (и, возможно, сеанс тоже). См. http://docs.grails.org/latest/ref/Domain%20Classes/withTransaction.html

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

В моих Grails приложений, я держу свои контроллеры действительно немым:

  1. вызова службы
  2. Возврат выход сервиса (возможно, форматированием).

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

@grails.transaction.Transactional 
class SomeService { 
    def saveA(A a) { 
     // This method will run in a transaction. 
     a.addToBs(new B(a: this)) 
     a.save() 
    } 
} 

И в контроллере ...

class SomeController { 
    def update() { 
     ... 
     someService.save(a) 
    } 
} 
+0

Спасибо за этот совет Эммануэль. Я подумал, что, возможно, по-прежнему можно правильно использовать эти крючки, но я проверю, чтобы операция была включена в сервис. – alexanderfranke

+0

Вы можете использовать эти перехватчики, но вам нужно будет обернуть использование GORM как в новом сеансе, так и в транзакции (я не помню, какой) с помощью 'DomainClass.withSession()' или 'DomainClass.withTransaction()', соответственно. Проблема заключается в том, что крючки выполняются за пределами @transaction. –

Смежные вопросы