java – 在hibernate中将散列函数委托给未初始化的委托会导致更
我有一个hashCode()的问题,它使用hibernate委托给未初始化的对象.
我的数据模型看起来如下(以下代码经过高度修剪以强调问题因此破坏,不要复制!): class Compound { @FetchType.EAGER Set<Part> parts = new HashSet<Part>(); String someUniqueName; public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((getSomeUniqueName() == null) ? 0 : getSomeUniqueName().hashCode()); return result; } } class Part { Compound compound; String someUniqueName; public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((getCompound() == null) ? 0 : getCompound().hashCode()); result = prime * result + ((getSomeUniqueName() == null) ? 0 : getSomeUniqueName().hashCode()); return result; } } 请注意,hashCode()的实现完全遵循in the hibernate documentation给出的建议. 现在,如果我加载一个Compound类型的对象,它会急切地加载带有部件的HasSet.这会调用部件上的hashCode(),然后调用复合体上的hashCode().但问题是,此时并非所有考虑用于创建复合的hashCode的值都可用.因此,部件的hashCode在初始化完成后改变,从而制动HashSet的合同并导致各种难以跟踪的错误(例如,在部件组中设置两次相同的对象). 所以我的问题是:避免这个问题的最简单的解决方案是什么(我想避免为自定义加载/初始化编写类)?我完全做错了吗? 编辑:我错过了什么吗?这似乎是一个基本问题,为什么我在任何地方都找不到任何关于它的东西?
和
编辑:这是加载发生时的堆栈跟踪(如果这有帮助).在那个时间点,属性someUniqueName为null,因此hashCode被错误地计算. Compound.getSomeUniqueName() line: 263 Compound.hashCode() line: 286 Part.hashCode() line: 123 HashMap<K,V>.put(K,V) line: 372 HashSet<E>.add(E) line: 200 HashSet<E>(AbstractCollection<E>).addAll(Collection<? extends E>) line: 305 PersistentSet.endRead() line: 352 CollectionLoadContext.endLoadingCollection(LoadingCollectionEntry,CollectionPersister) line: 261 CollectionLoadContext.endLoadingCollections(CollectionPersister,List) line: 246 CollectionLoadContext.endLoadingCollections(CollectionPersister) line: 219 EntityLoader(Loader).endCollectionLoad(Object,SessionImplementor,CollectionPersister) line: 1005 EntityLoader(Loader).initializeEntitiesAndCollections(List,Object,boolean) line: 993 EntityLoader(Loader).doQuery(SessionImplementor,QueryParameters,boolean) line: 857 EntityLoader(Loader).doQueryAndInitializeNonLazyCollections(SessionImplementor,boolean) line: 274 EntityLoader(Loader).loadEntity(SessionImplementor,Type,String,Serializable,EntityPersister,LockOptions) line: 2037 EntityLoader(AbstractEntityLoader).load(SessionImplementor,LockOptions) line: 86 EntityLoader(AbstractEntityLoader).load(Serializable,LockOptions) line: 76 SingleTableEntityPersister(AbstractEntityPersister).load(Serializable,LockOptions,SessionImplementor) line: 3293 DefaultLoadEventListener.loadFromDatasource(LoadEvent,EntityKey,LoadEventListener$LoadType) line: 496 DefaultLoadEventListener.doLoad(LoadEvent,LoadEventListener$LoadType) line: 477 DefaultLoadEventListener.load(LoadEvent,LoadEventListener$LoadType) line: 227 DefaultLoadEventListener.proxyOrLoad(LoadEvent,LoadEventListener$LoadType) line: 269 DefaultLoadEventListener.onLoad(LoadEvent,LoadEventListener$LoadType) line: 152 SessionImpl.fireLoad(LoadEvent,LoadEventListener$LoadType) line: 1090 SessionImpl.internalLoad(String,boolean,boolean) line: 1038 ManyToOneType(EntityType).resolveIdentifier(Serializable,SessionImplementor) line: 630 ManyToOneType(EntityType).resolve(Object,Object) line: 438 TwoPhaseLoad.initializeEntity(Object,PreLoadEvent,PostLoadEvent) line: 139 QueryLoader(Loader).initializeEntitiesAndCollections(List,boolean) line: 982 QueryLoader(Loader).doQuery(SessionImplementor,boolean) line: 857 QueryLoader(Loader).doQueryAndInitializeNonLazyCollections(SessionImplementor,boolean) line: 274 QueryLoader(Loader).doList(SessionImplementor,QueryParameters) line: 2542 QueryLoader(Loader).listIgnoreQueryCache(SessionImplementor,QueryParameters) line: 2276 QueryLoader(Loader).list(SessionImplementor,Set,Type[]) line: 2271 QueryLoader.list(SessionImplementor,QueryParameters) line: 459 QueryTranslatorImpl.list(SessionImplementor,QueryParameters) line: 365 HQLQueryPlan.performList(QueryParameters,SessionImplementor) line: 196 SessionImpl.list(String,QueryParameters) line: 1268 QueryImpl.list() line: 102 <my code where the query is executed> 解决方法
你有一个完美的合法用例,事实上它应该有效.但是,如果在设置’someUniqueName’之前设置Compound对象的’parts’,那么在常规Java中会遇到同样的问题.
因此,如果你能说服hibernate在’parts’属性之前设置’someUniqueName’属性.您是否尝试过在java类中重新排序它们?或者将“部分”重命名为“zparts”? hibernate文档只是说订单不能保证.我在hibernate中提交了一个错误,允许强制执行此命令… 另一种可能更容易的解决方案: class Part { public int hashCode() { //don't include getCompound().hashCode() return getSomeUniqueName() == null ? 0 : getSomeUniqueName().hashCode(); } public boolean equals(Object o) { if (this == o) return true; if (!o instanceof Part) return false; Part part = (Part) o; if (getCompound() != null ? !getCompound().equals(part.getCompound()) : part.getCompound()!= null) return false; if (getSomeUniqueName()!= null ? !getSomeUniqueName().equals(part.getSomeUniqueName()) : part.getSomeUniqueName()!= null) return false; return true; } } 在Compound.equals()中,确保它也以 public boolean equals(Object o) { if (this == o) return true; 这应该避免你现在遇到的问题. hashCode()方法中的每个属性都应该在equals()方法中,但不一定是相反的方式. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |