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

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

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;
}

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

Hibernate 6: JPA derived query methods failing when boolean mapping using YesNoConverter

I have the below entity where the deleted column in database is of type character with expected values 'Y' or 'N' . I'm using the YesNoConverter to encode the boolean value as 'Y' or 'N' .
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
.
.
#Column(name = "deleted")
#Convert(converter= YesNoConverter.class)
private boolean deleted;
}
But this code is giving error when I have a derived query method querying on the boolean property like below
public interface UserRepository extends JpaRepository<User,Long> {
List<User> findByDeletedFalse();
}
This repository method throws below exception
2023-02-14T10:30:30.160Z WARN 5796 --- [nio-9000-exec-5] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 42804
2023-02-14T10:30:30.160Z ERROR 5796 --- [nio-9000-exec-5] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: argument of NOT must be type boolean, not type character
Position: 128
2023-02-14T10:30:30.161Z ERROR 5796 --- [nio-9000-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.dao.InvalidDataAccessResourceUsageException: JDBC exception executing SQL [select u1_0.id,u1_0.deleted,u1_0.first_name,u1_0.home_address_id,u1_0.last_name,u1_0.work_address_id from users u1_0 where not(u1_0.deleted)]; SQL [n/a]] with root cause
org.postgresql.util.PSQLException: ERROR: argument of NOT must be type boolean, not type character
Position: 128
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2676) ~[postgresql-42.5.1.jar:42.5.1]
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2366) ~[postgresql-42.5.1.jar:42.5.1]
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:356) ~[postgresql-42.5.1.jar:42.5.1]
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:496) ~[postgresql-42.5.1.jar:42.5.1]
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:413) ~[postgresql-42.5.1.jar:42.5.1]
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:190) ~[postgresql-42.5.1.jar:42.5.1]
at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:134) ~[postgresql-42.5.1.jar:42.5.1]
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52) ~[HikariCP-5.0.1.jar:na]
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java) ~[HikariCP-5.0.1.jar:na]
at org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess.executeQuery(DeferredResultSetAccess.java:217) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess.getResultSet(DeferredResultSetAccess.java:146) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl.advanceNext(JdbcValuesResultSetImpl.java:205) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl.processNext(JdbcValuesResultSetImpl.java:85) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.sql.results.jdbc.internal.AbstractJdbcValues.next(AbstractJdbcValues.java:29) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.sql.results.internal.RowProcessingStateStandardImpl.next(RowProcessingStateStandardImpl.java:88) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:197) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:33) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:443) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:166) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:91) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
Hibernate: select u1_0.id,u1_0.deleted,u1_0.first_name,u1_0.home_address_id,u1_0.last_name,u1_0.work_address_id from users u1_0 where not(u1_0.deleted)
Code with this issue: https://github.com/chackomathew/spring-boot3-hibernate6/tree/boolean-converter-issue
Spring Boot v3.0.2
Hibernate v6.1.7.Final
If I provide JPQL query like below it's working fine.
#Query("select u from User u where u.deleted=false")
List<User> findByDeletedFalse();

Jpa failed to use update() when encountered existing record to save

Mysql database table structure:
database table structure
Customer.java class:
#JsonIgnore
#OneToMany(mappedBy = "customer")
private Set<OrderLine> orderLine = new HashSet<>();
Orderline.java class:
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "customer_id", referencedColumnName = "customer_id")})
private Customer customer;
Saving data through OrderLineController class:
#PostMapping("/orderLines")
public ResponseEntity<OrderLine> createOrderLine(#RequestBody OrderLine orderLine) {
OrderLine _orderLine = orderLineRepository.save(orderLine);
return new ResponseEntity<>(_orderLine, HttpStatus.CREATED);
}
Here is my Test file:
OrderLine newOL = new OrderLine(order, product);
newOL.setQty(1);
newOL.setCustomer(customer);
ResponseEntity<OrderLine> respOL = restTemplate.postForEntity("/api/orderLines", newOL, OrderLine.class);
assertEquals(HttpStatus.CREATED, respOL.getStatusCode());
I have previously populated an existing data in the Customer table, and now I tried to create new purchase order based on the existing customer.
In my Test file, when the save() function is executed, Jpa sees the "customer" as a new customer, but it was actually returned from the previous method:
ResponseEntity<Customer> getCustomersByCustomerId(String customerId)
Therefore trying to add a record with the same customer_id produced error, but indeed I was hoping the JpaRepository could figured out the customer_id is the same as the existing customer record, but it doesn't. The Jpa repository tried to insert this record into the customer table, thus resulting Duplicate entry error: I have been searching for possible solution for the past 5 days, but the issue still persist. Your help is much appreciated.
2022-10-06 23:36:23.722 DEBUG 16525 --- [o-auto-1-exec-3] org.hibernate.SQL :
insert
into
customer
(email_address, first_name, last_name, phone, customer_id)
values
(?, ?, ?, ?, ?)
Hibernate:
insert
into
customer
(email_address, first_name, last_name, phone, customer_id)
values
(?, ?, ?, ?, ?)
2022-10-06 23:36:23.726 TRACE 16525 --- [o-auto-1-exec-3] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [sammsonwonder#gmail.com]
2022-10-06 23:36:23.726 TRACE 16525 --- [o-auto-1-exec-3] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [VARCHAR] - [sammson]
2022-10-06 23:36:23.726 TRACE 16525 --- [o-auto-1-exec-3] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [VARCHAR] - [wonder]
2022-10-06 23:36:23.726 TRACE 16525 --- [o-auto-1-exec-3] o.h.type.descriptor.sql.BasicBinder : binding parameter [4] as [VARCHAR] - [0433233333]
2022-10-06 23:36:23.726 TRACE 16525 --- [o-auto-1-exec-3] o.h.type.descriptor.sql.BasicBinder : binding parameter [5] as [VARCHAR] - [0433233333]
2022-10-06 23:36:23.738 WARN 16525 --- [o-auto-1-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1062, SQLState: 23000
2022-10-06 23:36:23.739 ERROR 16525 --- [o-auto-1-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper : Duplicate entry '0433233333' for key 'customer.PRIMARY'
2022-10-06 23:36:23.744 INFO 16525 --- [o-auto-1-exec-3] o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements
[ERROR] Tests run: 6, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 2.886 s <<< FAILURE! - in dorinca.mm.rest.SavingsTest
[ERROR] create_1st_order_and_1x_product_for_existing_customer Time elapsed: 0.723 s <<< FAILURE!
org.opentest4j.AssertionFailedError: expected: <201 CREATED> but was: <500 INTERNAL_SERVER_ERROR>
at dorinca.mm.rest.SavingsTest.create_1st_order_and_1x_product_for_existing_customer(SavingsTest.java:179)

Lazy fetching in Spring JPA - different behaviour within cron and REST request

I have a little problem to understand why lazy fetching have different behaviour when I'm trying to execute 'findAll' method from REST controller and CRON job.
I have two simple entities:
#Entity
#Data
public class MainEntity {
#Id
#GeneratedValue(generator = "MainEntitySeqGen", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "MainEntitySeqGen", sequenceName = "main_entity_seq")
private Long id;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "main_id", foreignKey = #ForeignKey(name = "FK_mainEntity_nestedEntity"))
private Set<NestedEntity> nestedEntities;
}
and
#Entity
#Data
public class NestedEntity {
#Id
#GeneratedValue(generator = "NestedEntitySeqGen", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "NestedEntitySeqGen", sequenceName = "nested_entity_seq")
private Long id;
#Column
private String sample;
}
and service with method to find all 'MainEntities'. This service doesn't have any #Transactional annotations! (I don't have it in whole project)
#Override
public List<MainEntity> findAll() {
log.info("Finding all main entities...");
return repository.findAll();
}
I have one additional service to test lazy initialization exception with method:
#Override
public void testMe() {
List<MainEntity> entities = mainEntityService.findAll();
if (!entities.isEmpty()) {
log.info("Nested entities size: {}", entities.get(0).getNestedEntities().size());
}
}
Still no transactions on method or service!
Ok, and now, when I'm trying to execute testMe method from REST controller:
#GetMapping
public ResponseEntity<Void> testMe() {
log.info("Execution from API: Not throwing LazyInitializationException");
testService.testMe();
return ResponseEntity.ok().build();
}
I have correct output:
2022-05-01 00:04:42.396 INFO 11428 --- [nio-8080-exec-2] c.r.jpatest.web.FirstTestServiceApi : Execution from API: Not throwing LazyInitializationException
2022-05-01 00:04:42.396 INFO 11428 --- [nio-8080-exec-2] c.r.j.s.impl.MainEntityServiceImpl : Finding all main entities...
2022-05-01 00:04:42.396 TRACE 11428 --- [nio-8080-exec-2] o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll]
Hibernate: select mainentity0_.id as id1_0_ from main_entity mainentity0_
2022-05-01 00:04:42.397 TRACE 11428 --- [nio-8080-exec-2] o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll]
Hibernate: select nestedenti0_.main_id as main_id3_1_0_, nestedenti0_.id as id1_1_0_, nestedenti0_.id as id1_1_1_, nestedenti0_.sample as sample2_1_1_ from nested_entity nestedenti0_ where nestedenti0_.main_id=?
2022-05-01 00:04:42.408 INFO 11428 --- [nio-8080-exec-2] c.r.j.service.impl.TestServiceImpl : Nested entities size: 5
Please note that TransactionInterceptor says, he completed transaction for 'findAll' (from repository) but nevertheless he's invoking SELECT query to fetch NestedEntities that should be loaded lazily and I expected it throw exception (but not).
And this same 'testMe' method executed from CRON:
#Scheduled(cron = "*/10 * * * * *")
public void testCron() {
log.info("Execution from CRON: Throwing LazyInitializationException");
testService.testMe();
}
is throwing exception:
2022-05-01 00:04:50.014 INFO 11428 --- [ scheduling-1] c.r.jpatest.cronservices.TestCron : Execution from CRON: Throwing LazyInitializationException
2022-05-01 00:04:50.014 INFO 11428 --- [ scheduling-1] c.r.j.s.impl.MainEntityServiceImpl : Finding all main entities...
2022-05-01 00:04:50.014 TRACE 11428 --- [ scheduling-1] o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll]
Hibernate: select mainentity0_.id as id1_0_ from main_entity mainentity0_
2022-05-01 00:04:50.015 TRACE 11428 --- [ scheduling-1] o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll]
2022-05-01 00:04:50.016 ERROR 11428 --- [ scheduling-1] o.s.s.s.TaskUtils$LoggingErrorHandler : Unexpected error occurred in scheduled task
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.axl.jpatest.domain.MainEntity.nestedEntities, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:614) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:162) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final]
at org.hibernate.collection.internal.PersistentSet.size(PersistentSet.java:168) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final]
at com.axl.jpatest.service.impl.TestServiceImpl.testMe(TestServiceImpl.java:23) ~[classes/:na]
at com.axl.jpatest.cronservices.TestCron.testCron(TestCron.java:19) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:95) ~[spring-context-5.3.19.jar:5.3.19]
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[na:na]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Does anyone have idea why it works like that?
I use:
Spring Boot: v2.6.7
Hibernate: v5.6.8
I founded answer for this "problem" - cause is "Open Session In View" Spring mechanism.
Links:
#RestController methods seem to be Transactional by default, Why?
https://www.baeldung.com/spring-open-session-in-view
The error tell you that you're trying to fetch a lazy association, but there is no existing Hibernate Session for your current thread since you do it outside a transactional context.
Using JPA without delimiting your transaction boundaries explicitly with #Transactional is not a good thing because it creates an obscure code that creates a lot of short-lived Session and bypasses a lot of features that Hibernate offers you (session-level repeatable read, write-behind...)

using spring data jpa with spring boot issue

my entity Client
#Entity
public class Client implements Serializable {
#Id #GeneratedValue
private long code;
private String nom;
private String email;
#OneToMany(mappedBy = "client",fetch = FetchType.LAZY)
private Collection<Compte> comptes;
public Client(long code, String nom, String email, Collection<Compte> comptes) {
this.code = code;
this.nom = nom;
this.email = email;
this.comptes = comptes;
}
/...
getters and setters
}
entity Compte
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "TYPE_CPTE,",discriminatorType= DiscriminatorType.STRING,length = 2)
public abstract class Compte implements Serializable {
#Id
private String codeCompte;
private Date dataCreation;
private double solde;
#ManyToOne
#JoinColumn(name="CODE_CLI")
private Client client;
#OneToMany(mappedBy="compte")
private Collection<Operation> operations;
public Compte() {
super();
}
public Compte(String codeCompte, Date dataCreation, double solde, Client client, Collection<Operation> operations) {
this.codeCompte = codeCompte;
this.dataCreation = dataCreation;
this.solde = solde;
this.client = client;
this.operations = operations;
}
/...
getters and setters
}
entity Operation
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "TYPE_OP",discriminatorType = DiscriminatorType.STRING,length = 1)
public abstract class Operation implements Serializable{
#Id #GeneratedValue
private long numero;
private Date dateOperation;
private double montant;
#ManyToOne
#JoinColumn(name = "CODE_CPTE")
private Compte compte;
public Operation() {
super();
}
public Operation(Date dateOperation, double montant, Compte compte) {
this.dateOperation = dateOperation;
this.montant = montant;
this.compte = compte;
}
/...getters and setters
}
entity Retirer
#Entity
#DiscriminatorValue("R")
public class Retrait extends Operation {
public Retrait() {
}
public Retrait(Date dateOperation, double montant, Compte compte) {
super(dateOperation, montant, compte);
}
}
entity versement
#Entity
#DiscriminatorValue("V")
public class Versement extends Operation {
public Versement() {
}
public Versement(Date dateOperation, double montant, Compte compte) {
super(dateOperation, montant, compte);
}
}
entity Comptecourant
#Entity
#DiscriminatorValue("CE")
public class CompteEpargne extends Compte {
private double taux;
public CompteEpargne(String s, Date date, int i, Client c2, double taux) {
this.taux = taux;
}
public CompteEpargne(String codeCompte, Date dataCreation, double solde, Client client, Collection<Operation> operations, double taux) {
super(codeCompte, dataCreation, solde, client, operations);
this.taux = taux;
}
public CompteEpargne(){
super();
}
/...getters and setters
}
**entity CompteEpagne**
#Entity
#DiscriminatorValue("CC")
public class CompteCourant extends Compte {
private double decouvert;
public CompteCourant(String s, Date date, int i, Client c1, double decouvert) {
this.decouvert = decouvert;
}
public CompteCourant(String codeCompte, Date dataCreation, double solde, Client client, Collection<Operation> operations, double decouvert) {
super(codeCompte, dataCreation, solde, client, operations);
this.decouvert = decouvert;
}
public CompteCourant(){
super();
}
/...getters and setters
}
Repositorys
1
#Repository
public interface ClientRep extends JpaRepository<Client,Long> {
}
2
#Repository
public interface CompteRep extends JpaRepository<Compte,String> {
}
3
#Repository
public interface OperationRep extends JpaRepository<Operation,Long> {
#Query("select o from Operation o where o.compte.codeCompte=:x order by o.dateOperation desc ")
public Page<Operation> listOperation(String codeCpte, Pageable pageable);
}
service
public interface IBankMetier {
public Compte consulterCompte(String codeCpte);
public void verser(String codeCpte, double montant);
public void retirer(String codeCpte, double montant);
public void virement(String codeCpte1, String codeCpte2, double montant);
public Page<Operation> listOperation(String codeCpte, int page, int size);
}
implimantation
#Service
#Transactional
public class BankMetierImp implements IBankMetier {
#Autowired
private CompteRep compteRep;
#Autowired
private OperationRep operationRep;
#Override
public Compte consulterCompte(String codeCpte) {
Compte cp = compteRep.findOne(codeCpte);
if (cp == null) throw new RuntimeException("Compte introvable");
return cp;
}
#Override
public void verser(String codeCpte, double montant) {
Compte cp = consulterCompte(codeCpte);
Versement v = new Versement(new Date(), montant, cp);
operationRep.save(v);
cp.setSolde((cp.getSolde() + montant));
compteRep.save(cp);
}
#Override
public void retirer(String codeCpte, double montant) {
Compte cp = consulterCompte(codeCpte);
double facili = 0;
if (cp instanceof CompteCourant)
facili = ((CompteCourant) cp).getDecouvert();
if (cp.getSolde() + facili < montant)
throw new RuntimeException("solde insuffisant");
Retrait retrait = new Retrait(new Date(), montant, cp);
operationRep.save(retrait);
cp.setSolde((cp.getSolde() - montant));
compteRep.save(cp);
}
#Override
public void virement(String codeCpte1, String codeCpte2, double montant) {
retirer(codeCpte1, montant);
verser(codeCpte2, montant);
}
#Override
public Page<Operation> listOperation(String codeCpte, int page, int size) {
return operationRep.listOperation(codeCpte,new PageRequest(page,size));
}
}
Spring boot Application
#SpringBootApplication
public class MeinproApplication implements CommandLineRunner {
#Autowired
private ClientRep clientRep;
#Autowired
private CompteRep compteRep;
#Autowired
private OperationRep operationRep;
#Autowired
BankMetierImp bankMetier;
public static void main(String[] args) {
SpringApplication.run(MeinproApplication.class, args);
}
#Override
public void run(String... strings) throws Exception {
Client c1=clientRep.save(new Client("martin","martin#gmail.com"));
Client c2=clientRep.save(new Client("john","john#gmail.com"));
Compte cp1=compteRep.save(new CompteCourant("c1",new Date(),9000,c1,6000));
Compte cp2=compteRep.save(new CompteEpargne("c2",new Date(),63000,c2,12220));
operationRep.save(new Retrait(new Date(),6000,cp1));
operationRep.save(new Retrait(new Date(),10000,cp2));
operationRep.save(new Versement(new Date(),2000,cp1));
operationRep.save(new Versement(new Date(),20,cp2));
bankMetier.verser("c1",1000);
bankMetier.virement("c1","c2",2000);
}
}
application.properties
# DataSource settings:
spring.datasource.url=jdbc:mysql://localhost:3306/monbank
spring.datasource.username=roo
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
when I run it booom !!!!
2017-02-12 16:15:24.858 INFO 6232 --- [ restartedMain] org.hibernate.Version : HHH000412: Hibernate Core {5.0.11.Final}
2017-02-12 16:15:24.860 INFO 6232 --- [ restartedMain] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
2017-02-12 16:15:24.863 INFO 6232 --- [ restartedMain] org.hibernate.cfg.Environment : HHH000021: Bytecode provider name : javassist
2017-02-12 16:15:24.947 INFO 6232 --- [ restartedMain] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2017-02-12 16:15:25.113 INFO 6232 --- [ restartedMain] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
2017-02-12 16:15:25.938 INFO 6232 --- [ restartedMain] org.hibernate.tuple.PojoInstantiator : HHH000182: No default (no-argument) constructor for class: meinpro.entiti.Client (class must be instantiated by Interceptor)
2017-02-12 16:15:26.209 INFO 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000227: Running hbm2ddl schema export
Hibernate: alter table compte drop foreign key FK2hw4shqsxc782lychpkr52lmv
2017-02-12 16:15:26.228 ERROR 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: alter table compte drop foreign key FK2hw4shqsxc782lychpkr52lmv
2017-02-12 16:15:26.228 ERROR 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : Table 'monbank.compte' doesn't exist
Hibernate: alter table operation drop foreign key FKkr9nfjf0ipqrw5xwcf9jqq6gv
2017-02-12 16:15:26.229 ERROR 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: alter table operation drop foreign key FKkr9nfjf0ipqrw5xwcf9jqq6gv
2017-02-12 16:15:26.229 ERROR 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : Table 'monbank.operation' doesn't exist
Hibernate: drop table if exists client
Hibernate: drop table if exists compte
Hibernate: drop table if exists operation
Hibernate: create table client (code bigint not null auto_increment, email varchar(255), nom varchar(255), primary key (code))
Hibernate: create table compte (type_cpte, varchar(2) not null, code_compte varchar(255) not null, data_creation datetime, solde double precision not null, decouvert double precision, taux double precision, code_cli bigint, primary key (code_compte))
2017-02-12 16:15:26.712 ERROR 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: create table compte (type_cpte, varchar(2) not null, code_compte varchar(255) not null, data_creation datetime, solde double precision not null, decouvert double precision, taux double precision, code_cli bigint, primary key (code_compte))
2017-02-12 16:15:26.713 ERROR 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ' varchar(2) not null, code_compte varchar(255) not null, data_creation datetime,' at line 1
Hibernate: create table operation (type_op varchar(1) not null, numero bigint not null auto_increment, date_operation datetime, montant double precision not null, code_cpte varchar(255), primary key (numero))
Hibernate: alter table compte add constraint FK2hw4shqsxc782lychpkr52lmv foreign key (code_cli) references client (code)
2017-02-12 16:15:27.146 ERROR 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: alter table compte add constraint FK2hw4shqsxc782lychpkr52lmv foreign key (code_cli) references client (code)
2017-02-12 16:15:27.147 ERROR 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : Table 'monbank.compte' doesn't exist
Hibernate: alter table operation add constraint FKkr9nfjf0ipqrw5xwcf9jqq6gv foreign key (code_cpte) references compte (code_compte)
2017-02-12 16:15:27.330 ERROR 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: alter table operation add constraint FKkr9nfjf0ipqrw5xwcf9jqq6gv foreign key (code_cpte) references compte (code_compte)
2017-02-12 16:15:27.331 ERROR 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : Can't create table `monbank`.`#sql-23d4_77` (errno: 150 "Foreign key constraint is incorrectly formed")
2017-02-12 16:15:27.332 INFO 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000230: Schema export complete
2017-02-12 16:15:27.414 INFO 6232 --- [ restartedMain] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2017-02-12 16:15:27.938 INFO 6232 --- [ restartedMain] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
2017-02-12 16:15:28.776 INFO 6232 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for #ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#2ffb82a2: startup date [Sun Feb 12 16:15:18 PST 2017]; root of context hierarchy
2017-02-12 16:15:28.936 INFO 6232 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-02-12 16:15:28.938 INFO 6232 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-02-12 16:15:29.022 INFO 6232 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-02-12 16:15:29.022 INFO 6232 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-02-12 16:15:29.112 INFO 6232 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-02-12 16:15:29.263 WARN 6232 --- [ restartedMain] .t.AbstractTemplateResolverConfiguration : Cannot find template location: classpath:/templates/ (please add some templates or check your Thymeleaf configuration)
2017-02-12 16:15:30.063 INFO 6232 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2017-02-12 16:15:30.159 INFO 6232 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2017-02-12 16:15:30.246 INFO 6232 --- [ restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
Hibernate: insert into client (email, nom) values (?, ?)
Hibernate: insert into client (email, nom) values (?, ?)
2017-02-12 16:15:30.461 INFO 6232 --- [ restartedMain] utoConfigurationReportLoggingInitializer :
Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2017-02-12 16:15:30.472 ERROR 6232 --- [ restartedMain] o.s.boot.SpringApplication : Application startup failed
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:779) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:760) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:747) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at meinpro.MeinproApplication.main(MeinproApplication.java:30) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-1.5.1.RELEASE.jar:1.5.1.RELEASE]
Caused by: org.springframework.orm.jpa.JpaSystemException: ids for this class must be manually assigned before calling save(): meinpro.entiti.Compte; nested exception is org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): meinpro.entiti.Compte
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:333) ~[spring-orm-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244) ~[spring-orm-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:491) ~[spring-orm-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59) ~[spring-tx-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) ~[spring-tx-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147) ~[spring-tx-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133) ~[spring-data-jpa-1.11.0.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57) ~[spring-data-commons-1.13.0.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at com.sun.proxy.$Proxy86.save(Unknown Source) ~[na:na]
at meinpro.MeinproApplication.run(MeinproApplication.java:38) [classes/:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:776) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
... 11 common frames omitted
Caused by: org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): meinpro.entiti.Compte
at org.hibernate.id.Assigned.generate(Assigned.java:34) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:101) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67) ~[hibernate-entitymanager-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146) ~[hibernate-entitymanager-5.0.11.Final.jar:5.0.11.Final]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121]
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298) ~[spring-orm-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at com.sun.proxy.$Proxy82.persist(Unknown Source) ~[na:na]
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:508) ~[spring-data-jpa-1.11.0.RELEASE.jar:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:504) ~[spring-data-commons-1.13.0.RELEASE.jar:na]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:489) ~[spring-data-commons-1.13.0.RELEASE.jar:na]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461) ~[spring-data-commons-1.13.0.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61) ~[spring-data-commons-1.13.0.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.3.6.RELEASE.jar:4.3.6.RELEASE]
... 22 common frames omitted
2017-02-12 16:15:30.478 INFO 6232 --- [ restartedMain] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#2ffb82a2: startup date [Sun Feb 12 16:15:18 PST 2017]; root of context hierarchy
2017-02-12 16:15:30.483 INFO 6232 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
2017-02-12 16:15:30.485 INFO 6232 --- [ restartedMain] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2017-02-12 16:15:30.485 INFO 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000227: Running hbm2ddl schema export
Hibernate: alter table compte drop foreign key FK2hw4shqsxc782lychpkr52lmv
2017-02-12 16:15:30.488 ERROR 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: alter table compte drop foreign key FK2hw4shqsxc782lychpkr52lmv
2017-02-12 16:15:30.489 ERROR 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : Table 'monbank.compte' doesn't exist
Hibernate: alter table operation drop foreign key FKkr9nfjf0ipqrw5xwcf9jqq6gv
2017-02-12 16:15:30.499 ERROR 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: alter table operation drop foreign key FKkr9nfjf0ipqrw5xwcf9jqq6gv
2017-02-12 16:15:30.500 ERROR 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : Can't DROP 'FKkr9nfjf0ipqrw5xwcf9jqq6gv'; check that column/key exists
Hibernate: drop table if exists client
Hibernate: drop table if exists compte
Hibernate: drop table if exists operation
2017-02-12 16:15:30.879 INFO 6232 --- [ restartedMain] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000230: Schema export complete
Process finished with exit code 0
please help me
The error message is telling you exactly what the problem is
Caused by: org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): meinpro.entiti.Compte
The id in your Compte class is not a generated value, like the other tables
#Id
private String codeCompte;
So you need to set this value yourself before you save it.
Now look at the CompteEpargne and the CompteCourant (which extend Compte) constructors
public CompteEpargne(String s, Date date, int i, Client c2, double taux) {
this.taux = taux;
}
public CompteEpargne(String codeCompte, Date dataCreation, double solde, Client client, Collection<Operation> operations, double taux) {
super(codeCompte, dataCreation, solde, client, operations);
this.taux = taux;
}
public CompteCourant(String s, Date date, int i, Client c1, double decouvert) {
this.decouvert = decouvert;
}
public CompteCourant(String codeCompte, Date dataCreation, double solde, Client client, Collection<Operation> operations, double decouvert) {
super(codeCompte, dataCreation, solde, client, operations);
this.decouvert = decouvert;
}
The first constructor of each type only sets one value, while the second calls the super constructor, which set all the values (id included). When you are saving, you are using the first constructor
Compte cp1=compteRep.save(new CompteCourant("c1",new Date(),9000,c1,6000));
Compte cp2=compteRep.save(new CompteEpargne("c2",new Date(),63000,c2,12220));
You are calling the constructor that only sets one value. So you probably need to fix how that those constructors are setting properties. Maybe you want to do something like
public CompteEpargne(String s, Date date, int i, Client c2, double taux) {
this(s, date, i, c2, new ArrayList<Operation>(), taux);
}
where you call the other constructor.
Simple Solution
Your id attribute is not set. This may be due to the fact that the DB field is not set to auto increment.
For MySQL (as you have given in Properties file) use this below sample for defining your POJO class.
#Id #GeneratedValue(strategy = GenerationType.IDENTITY) #Column(name="id", unique=true, nullable=false) public Long getId() { return this.id; }
thanks friends the problem is in the class Compte
#DiscriminatorColumn(name = "TYPE_CPTE,",discriminatorType= DiscriminatorType.STRING,length = 2)
with in the name is ="TYPE_CPTE," hhhh I dont see the comma after TYPE_CPTE
#DiscriminatorColumn(name = "TYPE_CPTE",discriminatorType= DiscriminatorType.STRING,length = 2)

Spring Boot Hibernate Syntax Error in SQL Statement

I've modified the Spring Boot JPA Data example (https://github.com/spring-guides/gs-accessing-data-jpa.git) slightly adding an Order entity and a corresponding one to many mapping to it from the customer. When I run the example there are several Syntax Error in SQL Statement lines logged by Hibernate. I'm trying to figure out why? I've pasted the code for the entities and the console output from the application below.
package hello;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
#Entity
public class Customer {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
private String firstName;
private String lastName;
#OneToMany(mappedBy="customer")
private List<Order> orders;
protected Customer() {}
public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
#Override
public String toString() {
return String.format(
"Customer[id=%d, firstName='%s', lastName='%s']",
id, firstName, lastName);
}
}
And a corresponding Order entity:
package hello;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
#Entity
public class Order {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
protected Order() {}
double amount;
#ManyToOne
Customer customer;
}
And the console output:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.1.10.RELEASE)
2015-01-16 08:56:53.116 INFO 27810 --- [ main] hello.Application : Starting Application on MKI with PID 27810 (/home/ole/Documents/workspace-sts-3.6.3.RELEASE/gs-accessing-data-jpa-complete/target/classes started by ole in /home/ole/Documents/workspace-sts-3.6.3.RELEASE/gs-accessing-data-jpa-complete)
2015-01-16 08:56:53.149 INFO 27810 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext#5d59e6f1: startup date [Fri Jan 16 08:56:53 CST 2015]; root of context hierarchy
2015-01-16 08:56:54.253 INFO 27810 --- [ main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2015-01-16 08:56:54.269 INFO 27810 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
name: default
...]
2015-01-16 08:56:54.320 INFO 27810 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {4.3.7.Final}
2015-01-16 08:56:54.322 INFO 27810 --- [ main] org.hibernate.cfg.Environment : HHH000205: Loaded properties from resource hibernate.properties: {hibernate.connection.charSet=UTF-8, hibernate.dialect=org.hibernate.dialect.H2Dialect, hibernate.show_sql=true, hibernate.export.schema.delimiter=;, hibernate.bytecode.use_reflection_optimizer=false, hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy}
2015-01-16 08:56:54.322 INFO 27810 --- [ main] org.hibernate.cfg.Environment : HHH000021: Bytecode provider name : javassist
2015-01-16 08:56:54.462 INFO 27810 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {4.0.5.Final}
2015-01-16 08:56:54.499 INFO 27810 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2015-01-16 08:56:54.591 INFO 27810 --- [ main] o.h.h.i.ast.ASTQueryTranslatorFactory : HHH000397: Using ASTQueryTranslatorFactory
2015-01-16 08:56:54.751 INFO 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000227: Running hbm2ddl schema export
Hibernate: alter table order drop constraint FK_m6q2ofkj1g5aobtb2p00ajpqg if exists
2015-01-16 08:56:54.752 ERROR 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: alter table order drop constraint FK_m6q2ofkj1g5aobtb2p00ajpqg if exists
2015-01-16 08:56:54.753 ERROR 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : Syntax error in SQL statement "ALTER TABLE ORDER[*] DROP CONSTRAINT FK_M6Q2OFKJ1G5AOBTB2P00AJPQG IF EXISTS "; expected "identifier"; SQL statement:
alter table order drop constraint FK_m6q2ofkj1g5aobtb2p00ajpqg if exists [42001-176]
Hibernate: drop table customer if exists
Hibernate: drop table order if exists
2015-01-16 08:56:54.753 ERROR 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: drop table order if exists
2015-01-16 08:56:54.753 ERROR 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : Syntax error in SQL statement "DROP TABLE ORDER[*] IF EXISTS "; expected "identifier"; SQL statement:
drop table order if exists [42001-176]
Hibernate: create table customer (id bigint generated by default as identity, first_name varchar(255), last_name varchar(255), primary key (id))
Hibernate: create table order (id bigint generated by default as identity, amount double not null, customer_id bigint, primary key (id))
2015-01-16 08:56:54.756 ERROR 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: create table order (id bigint generated by default as identity, amount double not null, customer_id bigint, primary key (id))
2015-01-16 08:56:54.756 ERROR 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : Syntax error in SQL statement "CREATE TABLE ORDER[*] (ID BIGINT GENERATED BY DEFAULT AS IDENTITY, AMOUNT DOUBLE NOT NULL, CUSTOMER_ID BIGINT, PRIMARY KEY (ID)) "; expected "identifier"; SQL statement:
create table order (id bigint generated by default as identity, amount double not null, customer_id bigint, primary key (id)) [42001-176]
Hibernate: alter table order add constraint FK_m6q2ofkj1g5aobtb2p00ajpqg foreign key (customer_id) references customer
2015-01-16 08:56:54.757 ERROR 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: alter table order add constraint FK_m6q2ofkj1g5aobtb2p00ajpqg foreign key (customer_id) references customer
2015-01-16 08:56:54.757 ERROR 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : Syntax error in SQL statement "ALTER TABLE ORDER[*] ADD CONSTRAINT FK_M6Q2OFKJ1G5AOBTB2P00AJPQG FOREIGN KEY (CUSTOMER_ID) REFERENCES CUSTOMER "; expected "identifier"; SQL statement:
alter table order add constraint FK_m6q2ofkj1g5aobtb2p00ajpqg foreign key (customer_id) references customer [42001-176]
2015-01-16 08:56:54.757 INFO 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000230: Schema export complete
2015-01-16 08:56:55.085 INFO 27810 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2015-01-16 08:56:55.102 INFO 27810 --- [ main] hello.Application : Started Application in 2.286 seconds (JVM running for 2.604)
Hibernate: insert into customer (id, first_name, last_name) values (null, ?, ?)
Hibernate: insert into customer (id, first_name, last_name) values (null, ?, ?)
Hibernate: insert into customer (id, first_name, last_name) values (null, ?, ?)
Hibernate: insert into customer (id, first_name, last_name) values (null, ?, ?)
Hibernate: insert into customer (id, first_name, last_name) values (null, ?, ?)
Hibernate: select customer0_.id as id1_0_, customer0_.first_name as first_na2_0_, customer0_.last_name as last_nam3_0_ from customer customer0_
Customers found with findAll():
-------------------------------
Customer[id=1, firstName='Jack', lastName='Bauer']
Customer[id=2, firstName='Chloe', lastName='O'Brian']
Customer[id=3, firstName='Kim', lastName='Bauer']
Customer[id=4, firstName='David', lastName='Palmer']
Customer[id=5, firstName='Michelle', lastName='Dessler']
Hibernate: select customer0_.id as id1_0_0_, customer0_.first_name as first_na2_0_0_, customer0_.last_name as last_nam3_0_0_ from customer customer0_ where customer0_.id=?
Customer found with findOne(1L):
--------------------------------
Customer[id=1, firstName='Jack', lastName='Bauer']
Hibernate: select customer0_.id as id1_0_, customer0_.first_name as first_na2_0_, customer0_.last_name as last_nam3_0_ from customer customer0_ where customer0_.last_name=?
Customer found with findByLastName('Bauer'):
--------------------------------------------
Customer[id=1, firstName='Jack', lastName='Bauer']
Customer[id=3, firstName='Kim', lastName='Bauer']
Hibernate: select customer0_.id as id1_0_, customer0_.first_name as first_na2_0_, customer0_.last_name as last_nam3_0_ from customer customer0_
Hibernate: delete from customer where id=?
Hibernate: delete from customer where id=?
Hibernate: delete from customer where id=?
Hibernate: delete from customer where id=?
Hibernate: delete from customer where id=?
2015-01-16 08:56:55.258 INFO 27810 --- [ main] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext#5d59e6f1: startup date [Fri Jan 16 08:56:53 CST 2015]; root of context hierarchy
2015-01-16 08:56:55.259 INFO 27810 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
2015-01-16 08:56:55.260 INFO 27810 --- [ main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2015-01-16 08:56:55.261 INFO 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000227: Running hbm2ddl schema export
Hibernate: alter table order drop constraint FK_m6q2ofkj1g5aobtb2p00ajpqg if exists
2015-01-16 08:56:55.261 ERROR 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: alter table order drop constraint FK_m6q2ofkj1g5aobtb2p00ajpqg if exists
2015-01-16 08:56:55.261 ERROR 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : Syntax error in SQL statement "ALTER TABLE ORDER[*] DROP CONSTRAINT FK_M6Q2OFKJ1G5AOBTB2P00AJPQG IF EXISTS "; expected "identifier"; SQL statement:
alter table order drop constraint FK_m6q2ofkj1g5aobtb2p00ajpqg if exists [42001-176]
Hibernate: drop table customer if exists
Hibernate: drop table order if exists
2015-01-16 08:56:55.263 ERROR 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: drop table order if exists
2015-01-16 08:56:55.263 ERROR 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : Syntax error in SQL statement "DROP TABLE ORDER[*] IF EXISTS "; expected "identifier"; SQL statement:
drop table order if exists [42001-176]
2015-01-16 08:56:55.263 INFO 27810 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000230: Schema export complete
Thoughts?
TIA,
- Ole
Try change your Order entity please:
package hello;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table(name = "order_table")
public class Order {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
protected Order() {}
double amount;
#ManyToOne
Customer customer;
}
Explanation:
Pay attention on #Table annotation. Using this annotation I've specified table name as order_table. In your case by default hibernate tried to generate table order. ORDER is service word in any sql. Exception appeared because hibernate was generating *** statement for the order table but db expected table name not service word order.
I had the exact same problem with an Order entity, solved defining explicitly the table name.
#Entity
#Table(name = "order_table")
class Order(
#Id
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid2")
val orderId: String,
val customerId: String,
...
)
I had the same issue with a column named order but I was unable to change it. Adding backticks to the column annotation solved it.
#Column(name = "`ORDER`")
val order: String

Resources