Reputation: 171
Legacy database example (desc below):
I have the Parent table that has composite primary key, id1 autogenerated as SERIAL(1), id2 with only default value. Child table has exactly same primary key, that is also foreign key from Parent table.
Child table is something like "plus" table, or extanded Parent table. We need additional columns in PArent table but we cant change the Parent table. So they created for us Child table with additional information, add foreign key from Parent table to Child table and also make this composite key as primary :)
I try to map it in Grails this way:
Parent.groovy
package test
class Parent implements Serializable{
Integer id1
Integer id2
String parentDesc
static hasOne = [child: Child]
static mappedBy = [child: 'parent']
static constraints = {
child nullable:true
}
static mapping = {
table 'parent'
id composite: ['id1', 'id2']
id1 column: 'id1'
id2 column: 'id2'
parentDesc column: 'parent_desc'
}
}
Child.groovy
package test
import java.io.Serializable
class Child implements Serializable{
Integer id1
Integer id2
Parent parent
String childDesc
static belongsTo = [parent: Parent]
static mapping = {
table 'child'
id composite: ['id1', 'id2']
id1 column: 'id1'
id2 column: 'id2'
childDesc column: 'child_desc'
columns {
parent(insertable: false, updateable: false) {
column name: 'id1'
column name: 'id2'
}
}
}
} The Parent has one or zero Child with composite key id1, id2. The Child belongs to Parent (save and delete with parent), has foreign key Parent's primary key, and also this composite foreign key is also his primary key.
Hibernate cannot return values when there are some rows (empty table is no problem :) - I think that its same bug reported here (but this time already resolved).
Technical info: Database: MaxDB (legacy) also tested on H2 embedded
Full test project: dropbox
Stacktrace:
[2m2017-06-05 13:59:26.063[0;39m [31mERROR[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.g.web.errors.GrailsExceptionResolver [0;39m [2m:[0;39m NullPointerException occurred when processing request: [GET] /
Stacktrace follows:
java.lang.reflect.InvocationTargetException: null
at org.grails.core.DefaultGrailsControllerClass$ReflectionInvoker.invoke(DefaultGrailsControllerClass.java:211)
at org.grails.core.DefaultGrailsControllerClass.invoke(DefaultGrailsControllerClass.java:188)
at org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter.handle(UrlMappingsInfoHandlerAdapter.groovy:90)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException: null
at org.hibernate.persister.entity.AbstractEntityPersister.loadByUniqueKey(AbstractEntityPersister.java:2172)
at org.hibernate.type.EntityType.loadByUniqueKey(EntityType.java:692)
at org.hibernate.type.EntityType.resolve(EntityType.java:434)
at org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:151)
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:125)
at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:1139)
at org.hibernate.loader.Loader.processResultSet(Loader.java:998)
at org.hibernate.loader.Loader.doQuery(Loader.java:936)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:342)
at org.hibernate.loader.Loader.doList(Loader.java:2622)
at org.hibernate.loader.Loader.doList(Loader.java:2605)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2434)
at org.hibernate.loader.Loader.list(Loader.java:2429)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:109)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1787)
at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:363)
at org.grails.orm.hibernate.query.AbstractHibernateQuery.listForCriteria(AbstractHibernateQuery.java:700)
at org.grails.orm.hibernate.HibernateGormStaticApi$_list_closure1.doCall(HibernateGormStaticApi.groovy:87)
at org.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:286)
at org.grails.orm.hibernate.GrailsHibernateTemplate.execute(GrailsHibernateTemplate.java:230)
at org.grails.orm.hibernate.GrailsHibernateTemplate.execute(GrailsHibernateTemplate.java:116)
at org.grails.orm.hibernate.HibernateGormStaticApi.list(HibernateGormStaticApi.groovy:73)
at org.grails.orm.hibernate.HibernateGormStaticApi.list(HibernateGormStaticApi.groovy:72)
at org.grails.datastore.gorm.GormEntity$Trait$Helper.list(GormEntity.groovy:654)
at test.ParentController.$tt__index(ParentController.groovy:10)
at grails.transaction.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:96)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
at grails.transaction.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:93)
... 14 common frames omitted
Upvotes: 1
Views: 759
Reputation: 388
I know this question is somewhat old, but I had what I think is the same problem as yours.
Anyway, after some debugging and research, I got mine working. All I had to do was switch the fetch behavior to 'join' so it will fetch the parent and the child in the same sql query. Note that this could mean a performance bottleneck depeding on your use case.
static mapping = {
child fetch: 'join'
}
Edit: refresh()
still doesn't work though
Upvotes: 1