【发布时间】:2015-03-02 17:54:27
【问题描述】:
我正在使用 Grails 2.4.4。我想测试 具有内存数据库的单元测试类的持久性。 我有一个与 Child 有 oneToMany 关系的 Parent 类。 Child 由 Parent 拥有,并且具有涉及父级的复合键。当我尝试删除 Parent 内的集合中的一个 Children 时,如果我刷新,我会收到一个错误,如果我省略 'flush: true' 参数,则不会触发删除。
class Parent implements Serializable {
String name
static hasMany = [children : Child]
static mapping = {
children cascade: 'all-delete-orphan'
}
}
class OtherParent implements Serializable {
String name
}
class Child implements Serializable {
String name
static belongsTo = [ owner : Parent, secondOwner : OtherParent]
static mapping = {
id composite : ['owner', 'secondOwner']
}
}
我想在像这样注释的单元测试类中测试关系
@Domain([Parent, OtherParent, Child])
@TestMixin(HibernateTestMixin)
class ChildSpec extends Specification {
def "Parents and Children can be created, saved and deleted"() {
given: "we have a clean database at the start"
Parent.count() == 0
OtherParent.count() == 0
Child.count() == 0
and:
Parent a = new Parent()
a.name = "Parent"
OtherParent secondParent = new OtherParent ()
secondParent.name = 'Second Parent'
Child b = new Child()
b.name = "Child"
b.otherOwner = secondParent
a.addToChildren(b)
when: "we save Parent"
secondParent.save(flush: true, failOnError: true)
a.save(flush: true, failOnError: true)
then: "Parent saves and Child is saved too"
Parent.count() == 1
Child.count() == 1
def savedA = Parent.findByName("Parent")
savedA.name == "Parent"
savedA.children.size() == 1
def savedB = savedA.children.getAt(0)
savedB.name == "Child"
def foundB = Child.findByName("Child")
foundB.name == "Child"
when: "we remove Child from Parent, we can still save Parent"
savedA.removeFromChildren(savedB)
savedB.delete(flush: true)
savedA.save(failOnError: true, flush: true)
then: "we've got an Parent with no Bs and no exception is thrown"
notThrown(Exception)
Child.count() == 0
}
}
但是抛出异常
Expected no exception of type 'java.lang.Exception' to be thrown, but got it nevertheless
at spock.lang.Specification.notThrown(Specification.java:106)
at eu.europa.ec.comp.redda.test.ParentSpec.Parents and Chilren can be created, saved and deleted(ParentSpec.groovy:56)
Caused by: org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException: Object of class [eu.europa.ec.comp.redda.test.Child] with identifier [eu.europa.ec.comp.redda.test.Child : (unsaved)]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [eu.europa.ec.comp.redda.test.Child#eu.europa.ec.comp.redda.test.Child : (unsaved)]
at org.springframework.orm.hibernate4.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:200)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.convertHibernateAccessException(GrailsHibernateTemplate.java:593)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:183)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.execute(GrailsHibernateTemplate.java:123)
at org.codehaus.groovy.grails.orm.hibernate.InstanceApiHelper.delete(InstanceApiHelper.java:36)
at org.codehaus.groovy.grails.orm.hibernate.HibernateGormInstanceApi.delete(HibernateGormInstanceApi.groovy:228)
at eu.europa.ec.comp.redda.test.ParentSpec.Parents and Chilren can be created, saved and deleted(ParentSpec.groovy:52)
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [eu.europa.ec.comp.redda.test.Child#eu.europa.ec.comp.redda.test.Child : (unsaved)]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2541)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3403)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3630)
at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:114)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:349)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222)
at org.codehaus.groovy.grails.orm.hibernate.InstanceApiHelper$1.doInHibernate(InstanceApiHelper.java:40)
at org.codehaus.groovy.grails.orm.hibernate.InstanceApiHelper$1.doInHibernate(InstanceApiHelper.java:36)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:179)
... 4 more
【问题讨论】:
-
请问“我想在单元测试类中测试关系”是什么意思?我看不到您在测试中要达到的目标。
-
我想在单元测试类中,看看我是否可以正确地保持我的域类没有错误。问题是当我运行我的测试时,如果我只调用不带参数的 save 方法,那么 B 不会从数据库中删除。只有当我使用 flush:on 调用 save 方法时,集合中的 B 才会从数据库中删除。但如果我这样做,则会引发 StaleObjectStateException 异常。 (想看日志中的delete语句,不报错)
-
OK - 您的测试设置代码在哪里?即允许您执行此操作的代码
A.findByName(A_NAME)?另外,你想在这里做什么:def b = a.bs.find? -
我稍微改变了我的问题,添加了属性并更改了类的名称。根据约翰的回答,只是为了更清楚。
-
更新:添加了异常 StackTrace 和基于 John 回答的完整示例。
标签: grails one-to-many composite-key all-delete-orphan