Делегирование хеш-функции неинициализированным делегатам в спящем режиме вызывает изменение хэш-кода

У меня проблема с hashCode () , который делегирует неинициализированным объектам с помощью спящего режима .

Моя модель данных выглядит следующим образом (следующий код сильно сокращен, чтобы подчеркнуть проблему и поэтому сломан, не копируйте!):

class Compound {
  @FetchType.EAGER
  Set parts = new HashSet();

  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 () тщательно следует совету, приведенному в документации по спящему режиму .

Теперь, если я загружаю объект типа Compound , он охотно загружает HasSet с частями . Это вызывает hashCode () для частей, который, в свою очередь, вызывает hashCode () для соединения. Однако проблема в том, что на данном этапе не все значения, которые рассматриваются для создания хэш-кода соединения пока нет.Следовательно, хэш-код частей изменяется после завершения инициализации, тем самым нарушая контракт HashSet и приводя ко всем видам трудноотслеживаемых ошибок (например, наличие один и тот же объект в деталях установлен дважды).

Итак, мой вопрос: Какое простейшее решение избежать этой проблемы (я бы не хотел писать классы для пользовательской загрузки / инициализации)? Я что-то здесь делаю совсем не так?

Редактировать : Я что-то здесь упустил? Кажется, это основная проблема, почему я нигде не нахожу об этом ничего?

Вместо использования идентификатора базы данных для сравнения на равенство, вы должны использовать набор свойств для equals (), которые идентифицируют ваш отдельные объекты. [...] Нет необходимости использовать постоянный идентификатор, поэтому называется "бизнес-ключом" гораздо лучше. Это естественный ключ, но это раз нет ничего плохого в его использовании! ( статья из hibernate )

И

Рекомендуется реализовать equals () и hashCode (), используя Деловое равенство ключей. Равенство бизнес-ключей означает, что равенство () сравнивает только свойства, составляющие бизнес-ключ. это ключ, который идентифицировал бы наш экземпляр в реальном мире (естественный кандидат ключ). ( документация по спящему режиму )

Правка: Это трассировка стека при загрузке (в случае, если это помогает). В этот момент атрибут someUniqueName имеет значение NULL, и поэтому хэш-код вычисляется неправильно.

Compound.getSomeUniqueName() line: 263  
Compound.hashCode() line: 286   
Part.hashCode() line: 123   
HashMap.put(K, V) line: 372    
HashSet.add(E) line: 200 
HashSet(AbstractCollection).addAll(Collection) 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, SessionImplementor, boolean) line: 993  
EntityLoader(Loader).doQuery(SessionImplementor, QueryParameters, boolean) line: 857    
EntityLoader(Loader).doQueryAndInitializeNonLazyCollections(SessionImplementor, QueryParameters, boolean) line: 274 
EntityLoader(Loader).loadEntity(SessionImplementor, Object, Type, Object, String, Serializable, EntityPersister, LockOptions) line: 2037    
EntityLoader(AbstractEntityLoader).load(SessionImplementor, Object, Object, Serializable, LockOptions) line: 86 
EntityLoader(AbstractEntityLoader).load(Serializable, Object, SessionImplementor, LockOptions) line: 76 
SingleTableEntityPersister(AbstractEntityPersister).load(Serializable, Object, LockOptions, SessionImplementor) line: 3293  
DefaultLoadEventListener.loadFromDatasource(LoadEvent, EntityPersister, EntityKey, LoadEventListener$LoadType) line: 496    
DefaultLoadEventListener.doLoad(LoadEvent, EntityPersister, EntityKey, LoadEventListener$LoadType) line: 477    
DefaultLoadEventListener.load(LoadEvent, EntityPersister, EntityKey, LoadEventListener$LoadType) line: 227  
DefaultLoadEventListener.proxyOrLoad(LoadEvent, EntityPersister, EntityKey, LoadEventListener$LoadType) line: 269   
DefaultLoadEventListener.onLoad(LoadEvent, LoadEventListener$LoadType) line: 152    
SessionImpl.fireLoad(LoadEvent, LoadEventListener$LoadType) line: 1090  
SessionImpl.internalLoad(String, Serializable, boolean, boolean) line: 1038 
ManyToOneType(EntityType).resolveIdentifier(Serializable, SessionImplementor) line: 630 
ManyToOneType(EntityType).resolve(Object, SessionImplementor, Object) line: 438 
TwoPhaseLoad.initializeEntity(Object, boolean, SessionImplementor, PreLoadEvent, PostLoadEvent) line: 139   
QueryLoader(Loader).initializeEntitiesAndCollections(List, Object, SessionImplementor, boolean) line: 982   
QueryLoader(Loader).doQuery(SessionImplementor, QueryParameters, boolean) line: 857 
QueryLoader(Loader).doQueryAndInitializeNonLazyCollections(SessionImplementor, QueryParameters, boolean) line: 274  
QueryLoader(Loader).doList(SessionImplementor, QueryParameters) line: 2542  
QueryLoader(Loader).listIgnoreQueryCache(SessionImplementor, QueryParameters) line: 2276    
QueryLoader(Loader).list(SessionImplementor, QueryParameters, 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  

6
задан roesslerj 4 January 2012 в 17:15
поделиться