我最近从另一个人那里接手了Grails项目。
我正在使用Grails 3.2.11和Hibernate 4.3.10
我正在添加新功能,其中之一是扩展数据模型。有带有标签的故事,我想将它们组合到TagAliasGroups中。因此,我添加了:
import groovy.transform.EqualsAndHashCode
@EqualsAndHashCode
class TagAliasGroup {
Date created = new Date()
Set aliases
static hasMany = [aliases: Tag]
[...]
在Tag类中,我提到了这一点:
import groovy.transform.EqualsAndHashCode
@EqualsAndHashCode
class Tag {
String tag
Boolean promoted
Boolean isCategory
Date created = new Date()
TagAliasGroup aliasGroup
[...]
数据库架构已正确更新,我可以编写新的数据集。但是,当尝试访问TagAliasGroup中的“别名”集时,我在Hibernate中得到了无限的递归,并因此得到了StackOverflow异常:
def getAliasList() {
try
{
if(aliasGroup)
{
Set al = aliasGroup.aliases
// al.remove(this)
return al.join(", ")
}
else return ""
}
catch(Exception e){
return e.getMessage()
}
}
“return al.join(”,“)”引发异常,但是对Collection的任何其他访问都具有相同的结果。尝试评估“al”时,调试器也会获得异常。
在那时进入Hibernate时,在我看来,代码试图一遍又一遍地取消引用和解析TagAliasGroup的代理。
通过使“别名”成为 transient ,我做了一个简单的解决方法:
import groovy.transform.EqualsAndHashCode
@EqualsAndHashCode
class TagAliasGroup {
Date created = new Date()
// Set aliases
// static hasMany = [aliases: Tag]
def getAliases() {
return Tag.findAllByAliasGroup(this)
}
这是完美的工作,但它不是正确的解决方案。尤其是因为我希望休眠可以缓存结果,因此可以提高效率。
我想念什么?它一定很明显,但我不知道是什么。
这是异常(exception):
java.lang.StackOverflowError: null
at org.apache.commons.logging.impl.SLF4JLocationAwareLog.isDebugEnabled(SLF4JLocationAwareLog.java:67)
at org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy$LazyConnectionInvocationHandler.getTargetConnection(LazyConnectionDataSourceProxy.java:429)
at org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy$LazyConnectionInvocationHandler.invoke(LazyConnectionDataSourceProxy.java:376)
at org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy$TransactionAwareInvocationHandler.invoke(TransactionAwareDataSourceProxy.java:240)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:162)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:186)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:160)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.prepareQueryStatement(AbstractLoadPlanBasedLoader.java:257)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:201)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:137)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:102)
at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:100)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:693)
at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:92)
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1933)
at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:558)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:260)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:554)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:142)
at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:447)
at org.codehaus.groovy.util.HashCodeHelper.updateHash(HashCodeHelper.java:84)
at org.codehaus.groovy.util.HashCodeHelper.updateHash(HashCodeHelper.java:84)
at java.util.HashMap.hash(HashMap.java:339)
at java.util.HashMap.put(HashMap.java:612)
at java.util.HashSet.add(HashSet.java:220)
at java.util.AbstractCollection.addAll(AbstractCollection.java:344)
at org.hibernate.collection.internal.PersistentSet.endRead(PersistentSet.java:344)
at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:251)
at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:238)
at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:211)
at org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl.endLoading(CollectionReferenceInitializerImpl.java:168)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishLoadingCollections(AbstractRowReader.java:255)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:218)
at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:140)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:138)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:102)
at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:100)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:693)
at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:92)
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1933)
从这里不断地重复着。
最佳答案
在我使用hasMany,belongsTo或其他任何限定词的经验中,我将用这个答案作为前缀,这会导致更多的问题而不是有用的问题。除非您绝对需要它们提供的功能(级联,特定的休眠级别缓存等)。只需坚持使用Tag上的简单参考,然后从TagAliasGroup中删除“hasMany”,然后根据您的解决方法使用动态查找器加载标签即可。就是说,坚持您的设计,我认为您需要使用'belongsTo'来避免对给定标签进行对TagAliasGroup的循环反向引用的递归。
class Tag {
....
static belongsTo = [TagAliasGroup: aliasGroup]
....
}