0

I am trying to define a Grails domain model with abstract classes. I need to define two abstract classes that have a one-to-one bidirectional relationship with each other and can't bring them to work.

Explanation based on the Face-Nose example of the documentation:

I implemented the example and wrote a test that works as expected: if I set an end of the relationship, grails sets the other end.

class Face {
    static hasOne = [nose:Nose]

    static constraints = {
        nose nullable: true, unique:true
    }
}

class Nose {
    Face face
    static belongsTo = [Face]

    static constraints = {
        face nullable:true
    }
}


    when:'set a nose on the face'
        def testFace = new Face().save()
        def testNose = new Nose().save()

        testFace.nose = testNose
        testFace.save()

    then: 'bidirectional relationship'
        testFace.nose == testNose
        testNose.face == testFace

If I declare these two classes as abstract and repeat the same test with two concrete subclasses (ConcreteFace and ConcreteNose without any attribute), the second assertion is false: testNose.face is null.

Am I doing somthing wrong? If not, how can I factorize relationships in abstract domain classes?

1 Answers1

0

You have more save()'s than needed, and the logic inside Nose is wrong. First, the Face class is good as is; let's paste here for completion:

class Face {

   static hasOne = [nose:Nose]

   static constraints = {
      nose nullable:true, unique: true
   }
}

Next, Nose:

class Nose {

   static belongsTo = [face:Face]

   static constraints = {
   }
}

Note here that once you have the belongsTo relationship, you can't have face -- the parent -- be nullable in the constraints section.

Last, your integration test. Make sure it's an integration test and not just a unit test. Integration testing is needed when you're testing database-related logic (CRUD ops), not just mocking the ops which is what unit tests do. Here:

def "test bidirectionality integration"() {
   given: "a fresh face and nose"
   def face = new Face()
   def nose = new Nose(face:face)
   face.setNose(nose)

   when: "the fresh organs are saved"
   face.save()

   then: "bidirectionality is achieved"
   face.nose == nose
   nose.face == face
}

Note here that even a save for nose is not needed, saving face already persists nose. You may add the statement nose.save() after face.save() which would give you nothing here, but not before -- you can't save a child before it's parent is nicely settled in your tables.

Do that and you 'll get yourself one of these:

|Tests PASSED - view reports in ...
mohsenmadi
  • 2,277
  • 1
  • 23
  • 34
  • Hello mohsenmadi, thank you for your long answer. my problem isn't to define a bidirectional relation between two domain classes, it's to define a bidirectional relation between two abstract classes. I need to factorize this relation between a potentially large number of concrete classes. – Stefano Juri May 13 '15 at 06:56
  • First, I used the code you provided and added fixes to it. You had incorrectly designed tests and I pointed out the problem, again, in your code. Now, I don't know what you mean by **abstract classes** in the context of what you posted. If you mean abstract classes and inheritance then show code that reflects that so that we are on the same page. The problem, as you indicated at the end of your post, is the **null** value; that, at least, is fixed. – mohsenmadi May 13 '15 at 13:33