【问题标题】:Grails: 'integrity constraint violated' when child record was saved before the parent oneGrails:当子记录在父记录之前保存时“违反完整性约束”
【发布时间】:2013-08-11 18:16:03
【问题描述】:

在父记录之前保存子记录时出现异常:

GrailsWrappedRuntimeException: ORA-02291:
integrity constraint (GRB.FKF8F6B734389E9766) violated -
parent key not found

代码:

class Child {
    Parent parent
    static constraints = {
        parent nullable: true
    }
}

class Parent {
    static hasMany = [ children: Child ]
}

def child = new Child()
child.save() // first save of Child

def parent = new Parent()
parent.save()

//session.flush() // the sudden flush

child.parent = parent
child.save()

// here is 'constraint violation' when transaction is committed

正如异常消息中所说,Child 父键 Parent 已设置,但不知何故,该键在此时被 Hibernate 视为现有行...

以上是我的代码中发生的事件的简化重构。请注意,这些操作在不同的代码位置执行(设计为彼此分开)。不幸的是,这样的缩小代码运行良好并且不会重现问题......而且我以前从未遇到过这样的问题 - 我曾经在父记录之前保存子记录,反之亦然,没有任何问题。

我可以通过两种方式修复代码:

  • 评论Child 的“第一次保存”(保存顺序很重要?!)
  • 或取消注释会话刷新

虽然我可以修复它,但我真的不想依赖诸如保存顺序或突然刷新之类的东西......知道如何解决仍然有可靠代码的问题吗?

Grails 2.2.0、Hibernate 3.6、Oracle XE

【问题讨论】:

  • grails 允许使用动态方法将子对象保存在父对象中 parent.addToChildren(child)... 在这里查看更多信息.. gorm-gotchas
  • 你能把你的异常日志贴在这里吗?
  • 可能你的会话在父创建之前就被刷新了,没有真正的代码很难说错误在哪里。
  • 这个异常一点也不有趣:没有任何额外的信息(这对于 Oracle 端的约束违规是很常见的)。例如,当您在示例代码末尾执行 session.flush 时,它会引发。真正的代码是私有的,但样本代表了它的本质;也许我错过了什么……我会试试addTo,谢谢!

标签: oracle hibernate grails grails-orm


【解决方案1】:

您的异常可能是因为您在子表上没有可以为空的parent 约束进行了测试。如果没有可为空的,现有条目和新条目中将有 0 或其他内容,因为 DB 正在做一些魔术。 GORM 不会删除现有的 FK,也不会向现有列添加可为空的约束。尝试手动删除约束或删除整个列。仔细检查 parent_id 列上的可空约束。

关于您的问题,我建议您将孩子添加到父母身上,而不是将孩子保存为孩子:

parent.addToChildren(child)

如果之前没有保存过,这也会隐式保存孩子。

【讨论】:

    猜你喜欢
    • 2012-06-18
    • 2015-07-10
    • 2017-05-17
    • 2019-03-16
    • 2015-02-24
    • 1970-01-01
    • 2015-11-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多