问题
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.
回答1:
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.
回答2:
I have just created class structure as yours (Grails 2.1.0) and there is no problem. It works when mocked and unit-tested. The same when scaffolded and SomeClass and ThirdClass instances saved from forms. Try clean your DB, especially if you haven't used 'create-drop' mode. Maybe there is some old constraint left. Last thing, you haven't specified when the error occurs - on save (create or update)? It's rather not probable to get JDBC exception on property set, is it? I don't remember for sure but it's possible that simple property isn't cascaded by default then try to save SomeClass instance before saving the ThirdClass instance. Also you can auto-cascade instead of declaring simple property by use hasOne relation like:
class ThirdClass {
...
static hasOne = [baseProperty:BaseClass]
}
来源:https://stackoverflow.com/questions/12368364/grails-2-abstract-domain-inheritance-issue