【问题标题】:Fixtures Plugin Referential Integrity Exceptions In GrailsGrails 中的 Fixtures 插件引用完整性异常
【发布时间】:2013-08-10 14:19:30
【问题描述】:

我有一个对象 Foo,它与 Bar 和另一个与 Baz 具有双向一对一关系。当我尝试使用 Foo 执行 .load 并只给它一个 Bar 时,我收到引用完整性异常,抱怨没有 Baz。

真的应该这样吗?在现实世界的环境中,数据库中不可能没有任何匹配的 Baz 对象吗?

我尝试在固定装置负载关闭中手动设置 baz:null,但我仍然得到同样的结果。附带说明一下,当我只设置属性(例如简单的字符串)时,一切正常。只有当我开始建立关系时。

这是使用 Grails 2.2.4、Fixtures 1.2 且未安装 build-test-data 插件。

编辑:我有将 Baz 指定为可为空且唯一的约束。只是为了咯咯笑,我也尝试添加 blank 约束,但没有运气。

static constraints = {
    baz nullable:true, unique: true, blank: true
}

编辑 2:这是代码的简化版本:

class Foo {
    String someValue1
    String someValue2
    String whatever
    Bar bar
    Baz baz
    static mapping = {
        id composite: ['someValue1', 'someValue2'], generator: 'assigned'
        columns {
            bar([:]) { column name: 'some_other_value' }
            baz ([insertable:false, updateable: false]) {
                column name: 'some_value_1'
                column name: 'some_value_2'
            }
    }

    version: false

    static constraints = {
        //there are no constraints for Bar
        baz nullable:true, unique:true
    }
}

class Bar {
     String someOtherValue
     static hasMany = [foos:Foo]
     static mapping = { 
        id generator:'assigned', name:'someOtherValue'
     }
}

class Baz {
    String someValue1
    String someValue2
    String asdf

    static mapping = {
        id composite: ['some_value_1', 'some_value_2']
        version false
    }
}

class MyTest {
    def fixtureLoader
    @Before
    void setup() {
        fixureLoader.load {
            myBar(Bar, someOtherValue:"shibby")
            myFoo(Foo, someValue1:"test", someValue2:"test2", bar:myBar)
            //i also tried this
            //myFoo(Foo, someValue1:"test", someValue2:"test2", bar:myBar, baz:null)
        }
    }
}

这里是例外的一部分:

原因:org.h2.jdbc.JdbcBatchUpdateException:参照完整性 违反约束:“FK190E74B120F4F2BC:MYSCHEMA.FOO FOREIGN KEY(SOME_VALUE_1, SOME_VALUE_2) 参考 MYSCHEMA.BAZ(SOME_VALUE_1, SOME_VALUE_2)"; SQL 语句:插入到 MYSCHEMA.foo 中(无论如何, some_other_value, some_value_2, some_value_1) 值 (?, ?, ?, ?, ?, ?, ?, ?) [23506-164]

编辑:抱歉,我之前说错了。 Bar 与 Foo 是多对一的关系。

【问题讨论】:

  • 你能发布一个简单的失败例子吗?域类和装置会有所帮助
  • 好的,我刚发了。
  • 您将 Bar 上的 ID 设置为 generator:'assigned',但我没有看到任何地方设置了 id 值。这是否会导致 Bar 无法保存,从而在您保存 Foo 时会导致引用完整性约束?
  • myBar(Bar, someOtherValue:"shibby") 不是设置id吗?
  • hasMany 在 Bar w.r.t 中做了什么双向一对一关系?

标签: grails one-to-one fixtures referential-integrity bidirectional


【解决方案1】:

您的代码简化版本(Bar 中的 hasMany 除外)对我有效,没有任何 FK 异常。虽然如果我对父子映射正确无误,我更愿意采用不同的方法来实现真正的一对一双向关系。

以下是我的设置,它在没有 FK 约束异常的情况下运行良好。请注意,我在 cmets 中也提到了假设 Foo 有一个 Bar 和一个 Baz,我将如何实现真正的一对一双向。

class Foo implements Serializable{
    String someValue1
    String someValue2
    String whatever

    //True one to one can be achieved by doing as below
    //static hasOne = [bar: Bar, baz: Baz]

    Bar bar
    Baz baz

    static mapping = {
        id composite: ['someValue1', 'someValue2'], generator: 'assigned'
        columns {
            bar([:]) { column name: 'some_other_value' }
            baz ([insertable:false, updateable: false]) {
                column name: 'some_value_1'
                column name: 'some_value_2'
            }
        }
        version: false
    }

    static constraints = {
        //baz nullable:true, unique:true
    }
}

class Bar {
    String someOtherValue

    //True one to one can be achieved by doing as below
    //Below entry makes the relation bi-directional
    //Foo foo

    static mapping = {
        id generator:'assigned', name:'someOtherValue'
        //Optional, added for clarity
        someOtherValue column: 'some_other_value'
    }
}

class Baz implements Serializable{
    String someValue1
    String someValue2
    String asdf

    //True one to one can be achieved by doing as below
    //Below entry makes the relation bi-directional
    //Foo foo

    static mapping = {
        id composite: ['someValue1', 'someValue2']
        //Optional, added for clarity
        someValue1 column: 'some_value_1'
        someValue2 column: 'some_value_2'
        asdf column: 'asdf'

        version false
    }
}

class MyTests extends GroovyTestCase {
    def fixtureLoader

    void setUp() {
        fixtureLoader.load {
            myBar(Bar, someOtherValue:"shibby")
            myFoo(Foo, someValue1:"test", someValue2:"test2", 
                     whatever: "whatever", bar: myBar)
        }
    }

    void testSomething() {
        Foo.all.each{println it.properties}
        Bar.all.each{println it.properties}
    }
}

//Bootstrap Test in Dev mode
new Bar(someOtherValue: 'shibby').save()
new Foo(someValue1:"test", someValue2:"test2", 
        whatever: "whatever", bar: myBar).save(failOnError: true, flush: true)

注意事项

  • 上面我使用了您的确切简化代码,但在 Bar 中使用了 hasMany 关系。
  • Baz 上的约束是可选的。
  • 夹具按预期工作。
  • 按预期在 Foo 中创建列。
  • logSql 显示了预期的 DML。
  • 为了见证表的变化,我还在开发模式下按照run-app 引导了相同的测试数据。使用dbconsole,我能够看到预期的包含数据的表结构。
  • 遵循一对一双向的一般方式(称为注释代码),在子表 [BarBaz] 中创建 FK,因此您在示例代码中提供的显式映射不会坚持下去。
  • 如果提到关系的拥有方以及在 Bar 中拥有 hasMany 的理由,问题就会更加清楚。

【讨论】:

  • 我通过将 Foo 和 Baz 之间的关系更改为您所建议的真正的一对一关系来解决此问题。也就是说,静态的 hasOne = [baz:Baz] 在 Foo 上,在 Baz 上有一个 Foo 字段。感谢您实际尝试一下;有时需要有人说“它对我有用”:)
  • @AlexBeardsley 很高兴它有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-17
  • 2015-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多