Question

I have an object Foo that has a bidirectional one-to-one relationship with Bar and another one with Baz. When I try to do a .load with Foo and only give it a Bar, I get referential integrity exceptions complaining that there isn't a Baz.

Should this really be the case? In a real world environment isn't it possible that there wouldn't be any matching Baz object in the database?

I tried manually setting baz:null in the fixtures load closure, but I still get the same thing. On a side note, when I only set properties (such as a simple string), everything works fine. It's only when I start setting relationships.

This is with Grails 2.2.4, Fixtures 1.2, and without the build-test-data plugin installed.

EDIT: I have the constraints specifying Baz to be nullable and unique. Just for giggles I tried adding the blank constraint too, but no luck.

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

EDIT 2: Here is a simplified version of the code:

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

Here is part of the exception:

Caused by: org.h2.jdbc.JdbcBatchUpdateException: Referential integrity constraint violation: "FK190E74B120F4F2BC: MYSCHEMA.FOO FOREIGN KEY(SOME_VALUE_1, SOME_VALUE_2) REFERENCES MYSCHEMA.BAZ(SOME_VALUE_1, SOME_VALUE_2)"; SQL statement: insert into MYSCHEMA.foo (whatever, some_other_value, some_value_2, some_value_1) values (?, ?, ?, ?, ?, ?, ?, ?) [23506-164]

EDIT: Sorry, I misspoke earlier. Bar has a many-to-one relationship with Foo.

Was it helpful?

Solution

Your simplified version of code (except hasMany in Bar) works for me without any FK exception. Although I would prefer a different approach to achieve a true one-one bidirectional relationship if I am correct with the parent and child mapping.

Below is my setup which works fine without the FK constraint exception. Note that I have also mentioned in comments how would I achieve true one-to-one bidirectional assuming Foo has one Bar and has one 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)

Notes

  • Above I have used your exact simplified code but the hasMany relation in Bar.
  • Constraints on Baz is optional.
  • Fixtures works as expected.
  • Columns are created in Foo as expected.
  • logSql showed expected DML.
  • To witness the table changes, I also BootStraped the same test data in dev mode following a run-app. I was able to see the expected table structure with data in it, using dbconsole.
  • Following the general way of one-to-one bidirectional (mentioned as commented code), FKs are created in the child tables [Bar and Baz], so the explicit mapping you provided in the sample code would not hold good.
  • The question will be more clear if the owning side of the relationship and the rationale behind having hasMany in Bar is mentioned.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top