Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grails 2 abstract domain inheritance issue

The following is not working for me when using abstract (or non-abstract for that matter) inheritance in Grails.

Very quickly, my inheritance is as follows:

abstract BaseClass               { ... }
SomeClass      extends BaseClass { ... }
SomeOtherClass extends BaseClass { ... }

And then in another domain object:

ThirdClass {
    ...
    BaseClass baseProperty
    ...
}

But now, when I try to set that property to either a SomeClass or SomeOtherClass instance, Grails compains:

ERROR util.JDBCExceptionReporter - Cannot add or update a child row: a foreign key constraint fails ...

Is this not possible?


I have also tried having the base class not be abstract, and also tried casting the SomeClass or SomeOtherClass instances to BaseClass. They generate the same error.


UPDATE

I just checked. It works for the first sub-class that I add. But as soon as I try to add the other sub-class it fails.

In other words:

def prop1 = new ThirdClass(baseProperty: instanceOfSomeClass).save()

works fine. But when I then try and do:

def prop2 = new ThridClass(baseProperty: instanceOfSomeOtherClass).save()

it fails.


UPDATE 2

Further investigation shows that something goes wrong during the table creation process. It correctly adds two foreign keys to the ThirdClass table, but the keys incorrectly references:

CONSTRAINT `...` FOREIGN KEY (`some_id`) REFERENCES `base_class` (`id`),
CONSTRAINT `...` FOREIGN KEY (`some_id`) REFERENCES `some_class` (`id`)

Don't know why it's choosing the base class and one of the sub-classes? I have tried cleaning etc.

like image 655
Nico Huysamen Avatar asked Nov 30 '25 09:11

Nico Huysamen


1 Answers

First of all, create your BaseClass outside domain structure. It must be an external class, put it on script folder, source folder.

package com.example.model

/**
 * @author Inocencio
 */
class BaseClass {

    Date createdAt = new Date()

}

Now, create a regular domain class and extend it.

package com.example.domain

import com.example.model.BaseClass

class SomeClass extends BaseClass {

    String name

    static constraints = {
        name(nullable: false)
    }

}

As you can see, once you persist SomeClass a createdAt field is filled and saved as well. Check the test class out:

@TestFor(SomeClass)
class SomeClassTests {

    void testSomething() {
        def some = new SomeClass()
        some.name = "Hello There"
        some.save()

        //find it
        def someFind = SomeClass.list()[0]

        assert someFind

        assertTrue someFind.createdAt != null

//        println "Date: $someFind.createdAt"
//        println "Name: $someFind.name"
    }
}

I hope it can be helpful.

like image 104
Ito Avatar answered Dec 05 '25 08:12

Ito



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!