Home > database >  Spring-Data-JPA Hibernate: how to override/update a detached entity with the same ID?
Spring-Data-JPA Hibernate: how to override/update a detached entity with the same ID?

Time:06-18

I have to override/update a set of existing entities mapped by a cascade @OneToMany relationship from another class.

I would like to avoid having to previously load the existing entities and then save them for making them attached to the session.

@Data
@Entity
@Table(name = "my_asset")
public class MyAsset  {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    private Long id;


    @OneToMany(mappedBy = "myAsset",
        fetch = FetchType.EAGER,
        cascade = {CascadeType.ALL},
        orphanRemoval = true)
    private List<AssetComponent> components = new ArrayList<>();
}

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Entity
@SelectBeforeUpdate
@DynamicUpdate
@Table(name = "asset_component")
public class AssetComponent {
    @Id
    @EqualsAndHashCode.Include
    private UUID id;

    @Column(name = "model_id", nullable = false)
    private UUID modelID;

    @Column(nullable = false)
    private String type;

    @Column(nullable = false)
    private String name;

    @ManyToOne(optional = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    private MyAsset myAsset;
}

@Repository
public interface MyAssetRepository extends JpaRepository<MyAsset, Long> {}

Now, if I have an existing MyAsset with some existing components already in the DB, I cannot save the MyAsset directly:

MyAsset myAsset = new MyAsset();
myAsset.setComponents(Collections.singletonList(AssetComponent.builder()
        .id(UUID.fromString("b76d8a3b-2f0c-442a-bf50-58a19fce0fc9"))
        .modelID(UUID.fromString("22db9474-eeeb-4007-91a8-3e8bdfa9b83a"))
        .name("Component A")
        .type("Type A")
        .myAsset(myAsset)
    .build()));

myAssetRepository.save(myAsset);

because it gives me a stack of exceptions about the duplicate key exception with the AssetComponent ID:

  • org.springframework.dao.DataIntegrityViolationException
  • org.hibernate.exception.ConstraintViolationException
  • org.postgresql.util.PSQLException

How can I make the MyAsset & AssetComponent @Repository automatically merge the existing entities (if they have the same id) even if they have not been previously loaded from the DB?

Update

I created a GitHub repository to show you the minimum not working example: https://github.com/MaurizioCasciano/Spring-Data-JPA-Testing

I slightly changed the entities' name to make them as much general as possible: Container 1 --> N Item

I also enabled as much debugging as possible (at least i think so. Let me know if I can show more debugging info) using these properties:

spring:
  datasource:
    url: jdbc:h2:mem:test
    driver-class-name: org.h2.Driver
    username: test
    password: test
  h2:
    console:
      enabled: true
      path: /h2-console
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    properties:
      hibernate:
        show_sql: true
        format_sql: true
        use_sql_comments: true
logging:
  level:
    org.hibernate.type: trace

This is the simple @Test I'm running:

@SpringBootTest
public class ContainerRepositoryTests {
    @Autowired
    private ContainerRepository containerRepository;

    @Test
    public void testSaveContainer(){
        final UUID containerID = UUID.randomUUID();

        Container container = new Container();
        container.setId(containerID);

        Collection<Item> items = new HashSet<>();

        final UUID itemID = UUID.randomUUID();

        Item item = new Item();
        item.setId(itemID);
        item.setContainer(container);

        items.add(item);

        container.setItems(items);

        this.containerRepository.save(container);

        this.containerRepository.save(container);
    }
}

and it results in the following console output:

Hibernate: 


    drop table if exists container CASCADE 
Hibernate: 
    
    drop table if exists container_items CASCADE 
Hibernate: 
    
    drop table if exists item CASCADE 
Hibernate: 
    
    create table container (
       id binary(255) not null,
        primary key (id)
    )
Hibernate: 
    
    create table container_items (
       container_id binary(255) not null,
        items_id binary(255) not null
    )
Hibernate: 
    
    create table item (
       id binary(255) not null,
        container_id binary(255) not null,
        primary key (id)
    )
Hibernate: 
    
    alter table container_items 
       add constraint UK_tjc4gid6ob0h8pqhc9f4s1u9k unique (items_id)
Hibernate: 
    
    alter table container_items 
       add constraint FK3jaf77lxfykpono42ak2pqh7p 
       foreign key (items_id) 
       references item
Hibernate: 
    
    alter table container_items 
       add constraint FKt1xy6gjb3c94t8ifnjp36hsol 
       foreign key (container_id) 
       references container
Hibernate: 
    
    alter table item 
       add constraint FK9b9sc6vhhyquxqbixmhqtx0g 
       foreign key (container_id) 
       references container

Hibernate: 
    /* load org.testing.spring.data.jpa.domain.Container */ select
        container0_.id as id1_0_1_,
        items1_.container_id as containe1_1_3_,
        item2_.id as items_id2_1_3_,
        item2_.id as id1_2_0_,
        item2_.container_id as containe2_2_0_ 
    from
        container container0_ 
    left outer join
        container_items items1_ 
            on container0_.id=items1_.container_id 
    left outer join
        item item2_ 
            on items1_.items_id=item2_.id 
    where
        container0_.id=?
2022-06-10 09:36:41.066 TRACE 12924 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BINARY] - [b8718f19-8a5c-480a-bcb4-a116a74a0fd0]
Hibernate: 
    /* load org.testing.spring.data.jpa.domain.Item */ select
        item0_.id as id1_2_0_,
        item0_.container_id as containe2_2_0_ 
    from
        item item0_ 
    where
        item0_.id=?
2022-06-10 09:36:41.100 TRACE 12924 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BINARY] - [63050373-8b6b-4fca-8ead-49319ee0c1bb]
Hibernate: 
    /* insert org.testing.spring.data.jpa.domain.Container
        */ insert 
        into
            container
            (id) 
        values
            (?)
2022-06-10 09:36:41.121 TRACE 12924 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BINARY] - [b8718f19-8a5c-480a-bcb4-a116a74a0fd0]
Hibernate: 
    /* insert org.testing.spring.data.jpa.domain.Item
        */ insert 
        into
            item
            (container_id, id) 
        values
            (?, ?)
2022-06-10 09:36:41.124 TRACE 12924 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BINARY] - [b8718f19-8a5c-480a-bcb4-a116a74a0fd0]
2022-06-10 09:36:41.125 TRACE 12924 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [BINARY] - [63050373-8b6b-4fca-8ead-49319ee0c1bb]
Hibernate: 
    /* insert collection
        row org.testing.spring.data.jpa.domain.Container.items */ insert 
        into
            container_items
            (container_id, items_id) 
        values
            (?, ?)
2022-06-10 09:36:41.128 TRACE 12924 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BINARY] - [b8718f19-8a5c-480a-bcb4-a116a74a0fd0]
2022-06-10 09:36:41.128 TRACE 12924 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [BINARY] - [63050373-8b6b-4fca-8ead-49319ee0c1bb]
Hibernate: 
    /* load org.testing.spring.data.jpa.domain.Container */ select
        container0_.id as id1_0_1_,
        items1_.container_id as containe1_1_3_,
        item2_.id as items_id2_1_3_,
        item2_.id as id1_2_0_,
        item2_.container_id as containe2_2_0_ 
    from
        container container0_ 
    left outer join
        container_items items1_ 
            on container0_.id=items1_.container_id 
    left outer join
        item item2_ 
            on items1_.items_id=item2_.id 
    where
        container0_.id=?
2022-06-10 09:36:41.134 TRACE 12924 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BINARY] - [b8718f19-8a5c-480a-bcb4-a116a74a0fd0]
Hibernate: 
    /* load org.testing.spring.data.jpa.domain.Item */ select
        item0_.id as id1_2_0_,
        item0_.container_id as containe2_2_0_ 
    from
        item item0_ 
    where
        item0_.id=?
2022-06-10 09:36:41.137 TRACE 12924 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BINARY] - [63050373-8b6b-4fca-8ead-49319ee0c1bb]
Hibernate: 
    /* insert org.testing.spring.data.jpa.domain.Container
        */ insert 
        into
            container
            (id) 
        values
            (?)
2022-06-10 09:36:41.138 TRACE 12924 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BINARY] - [b8718f19-8a5c-480a-bcb4-a116a74a0fd0]
2022-06-10 09:36:41.141  WARN 12924 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 23505, SQLState: 23505
2022-06-10 09:36:41.142 ERROR 12924 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : Unique index or primary key violation: "PUBLIC.PRIMARY_KEY_8 ON PUBLIC.CONTAINER(ID) VALUES ( /* 1 */ CAST(X'b8718f198a5c480abcb4a116a74a0fd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' AS BINARY(255)) )"; SQL statement:
/* insert org.testing.spring.data.jpa [23505-212]
2022-06-10 09:36:41.142  INFO 12924 --- [           main] o.h.e.j.b.internal.AbstractBatchImpl     : HHH000010: On release of batch it still contained JDBC statements

org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["PUBLIC.PRIMARY_KEY_8 ON PUBLIC.CONTAINER(ID) VALUES ( /* 1 */ CAST(X'b8718f198a5c480abcb4a116a74a0fd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' AS BINARY(255)) )"; SQL statement:
/* insert org.testing.spring.data.jpa [23505-212]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement

    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:276)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:566)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:654)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:407)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
    at jdk.proxy2/jdk.proxy2.$Proxy111.save(Unknown Source)
    at org.testing.spring.data.jpa.repository.ContainerRepositoryTests.testSaveContainer(ContainerRepositoryTests.java:39)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    at java.base/java.lang.reflect.Method.invoke(Method.java:577)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
    at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
    at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
    at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
    at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:37)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:200)
    at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:46)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3375)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3908)
    at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:107)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
    at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478)
    at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:721)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:344)
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40)
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107)
    at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1407)
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:489)
    at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3290)
    at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2425)
    at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:449)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281)
    at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:562)
    ... 82 more
Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Unique index or primary key violation: "PUBLIC.PRIMARY_KEY_8 ON PUBLIC.CONTAINER(ID) VALUES ( /* 1 */ CAST(X'b8718f198a5c480abcb4a116a74a0fd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' AS BINARY(255)) )"; SQL statement:
/* insert org.testing.spring.data.jpa [23505-212]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:508)
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:477)
    at org.h2.message.DbException.get(DbException.java:223)
    at org.h2.message.DbException.get(DbException.java:199)
    at org.h2.index.Index.getDuplicateKeyException(Index.java:525)
    at org.h2.mvstore.db.MVSecondaryIndex.checkUnique(MVSecondaryIndex.java:223)
    at org.h2.mvstore.db.MVSecondaryIndex.add(MVSecondaryIndex.java:184)
    at org.h2.mvstore.db.MVTable.addRow(MVTable.java:519)
    at org.h2.command.dml.Insert.insertRows(Insert.java:174)
    at org.h2.command.dml.Insert.update(Insert.java:135)
    at org.h2.command.dml.DataChangeStatement.update(DataChangeStatement.java:74)
    at org.h2.command.CommandContainer.update(CommandContainer.java:174)
    at org.h2.command.Command.executeUpdate(Command.java:252)
    at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:209)
    at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:169)
    at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
    ... 103 more

CodePudding user response:

Hibernate already does select by id before saving detached entity. But the problem is that hibernate can't find entity by uuid. I don't know exactly how it works (it is possible that the problem is in the DBMS), but you can fix it by adding @Type annotation:

@Entity
public class Container {
    @Id
    @Type(type = "uuid-char")
    private UUID id;
}

CodePudding user response:

Spring Data JPA should already detect, that the entity is not new and should call merge.

You could make your entity implement Persistable which should fix the problem.

Alternatively, you could create a breakpoint in SimpleJpaRepository.save(..) and debug, why Spring Data JPA doesn't consider your entity new.

  • Related