[hibernate-dev] Issue with unidirectional one-to-many association with a join column that references a column that is not the primary key

2017-02-08 Thread Marcello Romano
Hi,

A one-to-many association is causing Hibernate to
throw the following exception when loading an entity via
Session.get(domainClass, identifier), under the following conditions:

1. the association collection is annotated with @Fetch(FetchMode.JOIN)
2. the association's join column is referencing a non-primary key of the
owning entity
3. the association's join column value is referencing a non-existing record
of the associated table (the "many" side).

Caused by: org.hibernate.property.access.spi.PropertyAccessException: Error
accessing field [protected java.lang.Long ...] by reflection for persistent
property [...] : 1GBE4E1E04
at
org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:43)
at
org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue(AbstractComponentTuplizer.java:58)
at org.hibernate.type.ComponentType.getPropertyValue(ComponentType.java:419)
at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:242)
at
org.hibernate.engine.spi.CollectionKey.generateHashCode(CollectionKey.java:64)
at org.hibernate.engine.spi.CollectionKey.(CollectionKey.java:58)
at org.hibernate.engine.spi.CollectionKey.(CollectionKey.java:43)
at
org.hibernate.engine.loading.internal.CollectionLoadContext.getLoadingCollection(CollectionLoadContext.java:95)
at
org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl.finishUpRow(CollectionReferenceInitializerImpl.java:105)
at
org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.readRow(AbstractRowReader.java:121)
at
org.hibernate.loader.plan.exec.internal.EntityLoadQueryDetails$EntityLoaderRowReader.readRow(EntityLoadQueryDetails.java:239)
at
org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:122)
at
org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:122)
at
org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86)
at
org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:167)
at
org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3967)
at
org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:508)
at
org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:478)
at
org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:219)
at
org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:278)
at
org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:121)
at
org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1129)
at org.hibernate.internal.SessionImpl.access$2600(SessionImpl.java:164)
at
org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2696)
at org.hibernate.internal.SessionImpl.get(SessionImpl.java:975)
...
Caused by: java.lang.IllegalArgumentException: Can not set ... to
java.lang.String
at
sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
at
sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
at
sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:55)
at
sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
at java.lang.reflect.Field.get(Field.java:379)
at
org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:39)
... 44 more


The problem is that when initializing the collection, Hibernate is not able
to retrieve the association key value in
CollectionReferenceInitializerImpl.finishUpRow and will fall back to use
the entity owner's primary key instead, causing the
IllegalArgumentException.

We have noticed that there is a related open issue:
https://hibernate.atlassian.net/browse/HHH-9370

We have worked around this issue by changing the way optionalKey is
retrieved in CollectionReferenceInitializerImpl.finishUpRow,
foreignKeyPropertyName );

ResultSetProcessingContext.EntityReferenceProcessingState ownerState =
context.getOwnerProcessingState( (Fetch) collectionReference );
Serializable optionalKey =
collectionReference.getCollectionPersister().getCollectionType().getKeyOfOwner(ownerState.getEntityInstance(),
context.getSession());


Although this seems to work for us, we would like to collaborate to have
this fixed upstream, if you believe this is actually caused by a bug and
not by using Hibernate associations in the wrong way.

Thanks,
Marcello
___
hibernate-dev mailing list
hibernate-dev@lists.jboss.org
https://lists.jboss.org/mailman/listinfo/hibernate-dev


Re: [hibernate-dev] Issue with unidirectional one-to-many association with a join column that references a column that is not the primary key

2017-02-08 Thread Marcello Romano
Hi Vlad,

I have created the following pull request with the test case:
https://github.com/hibernate/hibernate-orm/pull/1786

Thanks,
Marcello

On 8 February 2017 at 15:35, Vlad Mihalcea  wrote:

> Hi,
>
> You can send us a Pull Request on GitHub with a test case that replicates
> it, so we can discuss and integrate it.
>
> Vlad
>
> On Wed, Feb 8, 2017 at 10:11 PM, Marcello Romano 
> wrote:
>
>> Hi,
>>
>> A one-to-many association is causing Hibernate to
>> throw the following exception when loading an entity via
>> Session.get(domainClass, identifier), under the following conditions:
>>
>> 1. the association collection is annotated with @Fetch(FetchMode.JOIN)
>> 2. the association's join column is referencing a non-primary key of the
>> owning entity
>> 3. the association's join column value is referencing a non-existing
>> record
>> of the associated table (the "many" side).
>>
>> Caused by: org.hibernate.property.access.spi.PropertyAccessException:
>> Error
>> accessing field [protected java.lang.Long ...] by reflection for
>> persistent
>> property [...] : 1GBE4E1E04
>> at
>> org.hibernate.property.access.spi.GetterFieldImpl.get(Getter
>> FieldImpl.java:43)
>> at
>> org.hibernate.tuple.component.AbstractComponentTuplizer.getP
>> ropertyValue(AbstractComponentTuplizer.java:58)
>> at org.hibernate.type.ComponentType.getPropertyValue(ComponentT
>> ype.java:419)
>> at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:242)
>> at
>> org.hibernate.engine.spi.CollectionKey.generateHashCode(Coll
>> ectionKey.java:64)
>> at org.hibernate.engine.spi.CollectionKey.(CollectionKey.java:58)
>> at org.hibernate.engine.spi.CollectionKey.(CollectionKey.java:43)
>> at
>> org.hibernate.engine.loading.internal.CollectionLoadContext.
>> getLoadingCollection(CollectionLoadContext.java:95)
>> at
>> org.hibernate.loader.plan.exec.process.internal.CollectionRe
>> ferenceInitializerImpl.finishUpRow(CollectionReferenc
>> eInitializerImpl.java:105)
>> at
>> org.hibernate.loader.plan.exec.process.internal.AbstractRowR
>> eader.readRow(AbstractRowReader.java:121)
>> at
>> org.hibernate.loader.plan.exec.internal.EntityLoadQueryDetai
>> ls$EntityLoaderRowReader.readRow(EntityLoadQueryDetails.java:239)
>> at
>> org.hibernate.loader.plan.exec.process.internal.ResultSetPro
>> cessorImpl.extractResults(ResultSetProcessorImpl.java:122)
>> at
>> org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBase
>> dLoader.executeLoad(AbstractLoadPlanBasedLoader.java:122)
>> at
>> org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBase
>> dLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86)
>> at
>> org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntity
>> Loader.load(AbstractLoadPlanBasedEntityLoader.java:167)
>> at
>> org.hibernate.persister.entity.AbstractEntityPersister.load(
>> AbstractEntityPersister.java:3967)
>> at
>> org.hibernate.event.internal.DefaultLoadEventListener.loadFr
>> omDatasource(DefaultLoadEventListener.java:508)
>> at
>> org.hibernate.event.internal.DefaultLoadEventListener.doLoad
>> (DefaultLoadEventListener.java:478)
>> at
>> org.hibernate.event.internal.DefaultLoadEventListener.load(D
>> efaultLoadEventListener.java:219)
>> at
>> org.hibernate.event.internal.DefaultLoadEventListener.proxyO
>> rLoad(DefaultLoadEventListener.java:278)
>> at
>> org.hibernate.event.internal.DefaultLoadEventListener.doOnLo
>> ad(DefaultLoadEventListener.java:121)
>> at
>> org.hibernate.event.internal.DefaultLoadEventListener.onLoad
>> (DefaultLoadEventListener.java:89)
>> at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1129)
>> at org.hibernate.internal.SessionImpl.access$2600(SessionImpl.java:164)
>> at
>> org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.
>> load(SessionImpl.java:2696)
>> at org.hibernate.internal.SessionImpl.get(SessionImpl.java:975)
>> ...
>> Caused by: java.lang.IllegalArgumentException: Can not set ... to
>> java.lang.String
>> at
>> sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(
>> UnsafeFieldAccessorImpl.java:164)
>> at
>> sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(
>> UnsafeFieldAccessorImpl.java:168)
>> at
>> sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAcc
>> essorImpl.java:55)
>> at
>> sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFi
>> eldAccessorI