spring-projects / spring-data-relational

Spring Data Relational. Home of Spring Data JDBC and Spring Data R2DBC.
https://spring.io/projects/spring-data-jdbc
Apache License 2.0
740 stars 342 forks source link

MappedCollection select 2 level entity aggregate link by 1 level enity id value #1748

Closed RD-1-2020 closed 3 months ago

RD-1-2020 commented 4 months ago

Hello, after up version to 3.2.0, i have strange problem with my entity.

Pls help me understand, this is bug or my mistake)

Code

Naming all of entities and columns are correct.

My 1 level Entity is:


@Table("profiles")
public class ProfileEntity {
    /**
     * ID.
     */
    @Id
    @Column("id")
    private final long profileId;

    @Column("profile_id")
    private PermissionEntity permission;
}

My 2 level Entity is: table "permissions" has link to "profiles" in column "permissions.profile_id"


@Table("permissions")
public class PermissionEntity {
    @Id
    private long id;

    @MappedCollection(idColumn = "permission_id", keyColumn = "permission_attributes_id")
    private List<PermissionAttributeRef> permissionAttributesId = new ArrayList<>();
}

And linked entity is:

@Table("permissions_to_permission_attributes")
public class PermissionAttributeRef {

    private AggregateReference<FlowTypeRelation, Long> permissionAttributesId;
}

Problem description

At runtime when spring data jdbc try select ProfileEntity then select PermissionEntity and select PermissionAttributeRef by permission_id where permission_id = profiles.id. What I think is wrong. I think PermissionAttributeRef should be selected by permissions.id, but spring data jdbc select by profiles.id (1 level entity).

        var profile = profileRepository.findById(key).orElse(null);

        List<Long> permissionAttrIds = profile.getPermission().getPermissionAttributesId()
                .stream()
                .map(ref -> ref.getPermissionAttributesId().getId())
                .toList();

        // In this way 'permissionAttrIds' is empty

Temproary fix

Select ProfileEntity get from entity PermissionEntity.id and then more one select PermissionEntity and get permissionAttributesId in this way always work is correct, but i think this wrong way.

        var profile = profileRepository.findById(key).orElse(null);

        List<Long> permissionAttrIds = permissionsRepository.findById(
                profile.getPermission()
                        .getId())
                .get().getPermissionAttributesId()
                .stream()
                .map(ref -> ref.getPermissionAttributesId().getId())
                .toList();

        // In this way 'permissionAttrIds' is not empty

Images from debug

изображение изображение

My Thread dump

hz.qwertyprjservice.cached.thread-9@21645" tid=0x18f nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:91)
      at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61)
      at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:733)
      at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:658)
      at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:723)
      at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:748)
      at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:804)
      at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:218)
      at org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy.findAllByPath(DefaultDataAccessStrategy.java:306)
      at java.lang.invoke.LambdaForm$DMH/0x00000291ce934400.invokeInterface(LambdaForm$DMH:-1)
      at java.lang.invoke.LambdaForm$MH/0x00000291cec5c400.invoke(LambdaForm$MH:-1)
      at java.lang.invoke.LambdaForm$MH/0x00000291ce002400.invokeExact_MT(LambdaForm$MH:-1)
      at jdk.internal.reflect.DirectMethodHandleAccessor.invokeImpl(DirectMethodHandleAccessor.java:155)
      at jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
      at java.lang.reflect.Method.invoke(Method.java:580)
      at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:351)
      at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
      at jdk.proxy2.$Proxy121.findAllByPath(Unknown Source:-1)
      at org.springframework.data.jdbc.core.convert.MappingJdbcConverter$ResolvingRelationalPropertyValueProvider.getPropertyValue(MappingJdbcConverter.java:379)
      at org.springframework.data.jdbc.core.convert.MappingJdbcConverter$ResolvingRelationalPropertyValueProvider.getPropertyValue(MappingJdbcConverter.java:310)
      at org.springframework.data.relational.core.conversion.MappingRelationalConverter.readProperties(MappingRelationalConverter.java:555)
      at org.springframework.data.relational.core.conversion.MappingRelationalConverter.populateProperties(MappingRelationalConverter.java:522)
      at org.springframework.data.relational.core.conversion.MappingRelationalConverter.read(MappingRelationalConverter.java:456)
      at org.springframework.data.relational.core.conversion.MappingRelationalConverter.readAggregate(MappingRelationalConverter.java:348)
      at org.springframework.data.jdbc.core.convert.MappingJdbcConverter.access$000(MappingJdbcConverter.java:68)
      at org.springframework.data.jdbc.core.convert.MappingJdbcConverter$ResolvingRelationalPropertyValueProvider.getPropertyValue(MappingJdbcConverter.java:398)
      at org.springframework.data.jdbc.core.convert.MappingJdbcConverter$ResolvingRelationalPropertyValueProvider.getPropertyValue(MappingJdbcConverter.java:310)
      at org.springframework.data.relational.core.conversion.MappingRelationalConverter.readProperties(MappingRelationalConverter.java:555)
      at org.springframework.data.relational.core.conversion.MappingRelationalConverter.populateProperties(MappingRelationalConverter.java:522)
      at org.springframework.data.relational.core.conversion.MappingRelationalConverter.read(MappingRelationalConverter.java:456)
      at org.springframework.data.relational.core.conversion.MappingRelationalConverter.readAggregate(MappingRelationalConverter.java:348)
      at org.springframework.data.relational.core.conversion.MappingRelationalConverter.readAggregate(MappingRelationalConverter.java:311)
      at org.springframework.data.jdbc.core.convert.MappingJdbcConverter.readAndResolve(MappingJdbcConverter.java:287)
      at org.springframework.data.jdbc.core.convert.JdbcConverter.readAndResolve(JdbcConverter.java:106)
      at org.springframework.data.jdbc.core.convert.EntityRowMapper.mapRow(EntityRowMapper.java:82)
      at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94)
      at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61)
      at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:733)
      at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:658)
      at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:723)
      at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:748)
      at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:804)
      at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForObject(NamedParameterJdbcTemplate.java:252)
      at org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy.findById(DefaultDataAccessStrategy.java:268)
      at org.springframework.data.jdbc.core.JdbcAggregateTemplate.findById(JdbcAggregateTemplate.java:290)
      at org.springframework.data.jdbc.repository.support.SimpleJdbcRepository.findById(SimpleJdbcRepository.java:79)
      at java.lang.invoke.LambdaForm$DMH/0x00000291ce170c00.invokeVirtual(LambdaForm$DMH:-1)
      at java.lang.invoke.LambdaForm$MH/0x00000291cec94800.invoke(LambdaForm$MH:-1)
      at java.lang.invoke.Invokers$Holder.invokeExact_MT(Invokers$Holder:-1)
      at jdk.internal.reflect.DirectMethodHandleAccessor.invokeImpl(DirectMethodHandleAccessor.java:154)
      at jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
      at java.lang.reflect.Method.invoke(Method.java:580)
      at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:351)
      at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:277)
      at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker$$Lambda/0x00000291ce99b180.invoke(Unknown Source:-1)
      at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:170)
      at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:158)
      at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:516)
      at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285)
      at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:628)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
      at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:168)
      at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
      at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
      at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:385)
      at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
      at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
      at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
      at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:220)
      at jdk.proxy2.$Proxy122.findById(Unknown Source:-1)
      at java.lang.invoke.LambdaForm$DMH/0x00000291ce104000.invokeInterface(LambdaForm$DMH:-1)
      at java.lang.invoke.LambdaForm$MH/0x00000291cec94400.invoke(LambdaForm$MH:-1)
      at java.lang.invoke.Invokers$Holder.invokeExact_MT(Invokers$Holder:-1)
      at jdk.internal.reflect.DirectMethodHandleAccessor.invokeImpl(DirectMethodHandleAccessor.java:154)
      at jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
      at java.lang.reflect.Method.invoke(Method.java:580)
      at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:351)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
      at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
      at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:220)
      at jdk.proxy2.$Proxy122.findById(Unknown Source:-1)
      at org.qwe.qwertyprj.qwertyprjservice.services.network.DeviceProfileLoader.load(DeviceProfileLoader.java:88)
      at org.qwe.qwertyprj.qwertyprjservice.services.network.DeviceProfileLoader.load(DeviceProfileLoader.java:41)
      at com.hazelcast.map.impl.MapStoreWrapper.load(MapStoreWrapper.java:164)
      at com.hazelcast.map.impl.mapstore.writethrough.WriteThroughStore.load(WriteThroughStore.java:88)
      at com.hazelcast.map.impl.mapstore.writethrough.WriteThroughStore.load(WriteThroughStore.java:31)
      at com.hazelcast.map.impl.operation.steps.GetOpSteps$2.runStep(GetOpSteps.java:57)
      at com.hazelcast.map.impl.operation.steps.GetOpSteps$2.runStep(GetOpSteps.java:48)
      at com.hazelcast.map.impl.operation.steps.engine.StepSupplier.runStepWithState(StepSupplier.java:187)
      at com.hazelcast.map.impl.operation.steps.engine.StepSupplier.access$100(StepSupplier.java:40)
      at com.hazelcast.map.impl.operation.steps.engine.StepSupplier$2.run(StepSupplier.java:136)
      at com.hazelcast.map.impl.operation.steps.engine.StepRunner.runDirect(StepRunner.java:231)
      at com.hazelcast.map.impl.operation.steps.engine.StepRunner.run(StepRunner.java:174)
      at com.hazelcast.internal.util.executor.CachedExecutorServiceDelegate$Worker.run(CachedExecutorServiceDelegate.java:217)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
      at java.lang.Thread.runWith(Thread.java:1596)
      at java.lang.Thread.run(Thread.java:1583)
      at com.hazelcast.internal.util.executor.HazelcastManagedThread.executeRun(HazelcastManagedThread.java:76)
      at com.hazelcast.internal.util.executor.HazelcastManagedThread.run(HazelcastManagedThread.java:111)
schauder commented 4 months ago

This certainly looks like a bug. But could you please provide a reproducer, preferable as a github repository.

schauder commented 4 months ago

It might be a duplicate of #1734

RD-1-2020 commented 4 months ago

This certainly looks like a bug. But could you please provide a reproducer, preferable as a github repository.

Okay, thank you for your answer, I will create a repository on GitHub with a reproduction of this problem, and I will send a link soon.

schauder commented 3 months ago

There is a snapshot available that fixes #1692 3.3.0-1692-collection-in-embedded-SNAPSHOT And a PR to go with it: #1773

I assume this issue will be fixed by it as well. If nobody objects I'll close this issue as a duplicate once the PR is merged.

schauder commented 3 months ago

Duplicate of #1692