I am trying to persist a simple class using Spring, with hibernate/JPA and a PostgreSQL database.
The ID
column of the table is a UUID, which I want to generate in code, not in the database.
This should be straightforward since hibernate and postgres have good support for UUIDs.
Each time I create a new instance and write it with save()
, I get the following error:
o.h.j.JdbcSQLIntegrityConstraintViolationException: NULL not allowed for column "ID"; SQL statement: INSERT INTO DOODAHS (fieldA, fieldB) VALUES $1, $2) ...
This error indicates that it's expecting the ID column to be auto-populated (with some default value) when a row is inserted.
The class looks like this:
@lombok.Data
@lombok.AllArgsConstructor
@org.springframework.data.relational.core.mapping.Table("doodahs")
public class Doodah {
@org.springframework.data.annotation.Id
@javax.persistence.GeneratedValue(generator = "UUID")
@org.hibernate.annotations.GenericGenerator(name="UUID", strategy = "uuid2")
@javax.persistence.Column(nullable = false, unique = true)
private UUID id;
//... other fields
Things I have tried:
- Annotate the field with
@javax.persistence.Id
(in addition to existing spring Id) - Annotate the field with
@org.hibernate.annotations.Type(type = "pg-uuid")
- Create the UUID myself - results in Spring complaining that it can't find the row with that id.
- Specify
strategy = "org.hibernate.id.UUIDGenerator"
- Annotate class with
@Entity
- Replace spring
@Id
annotation with@javax.persistence.Id
I've seen useful answers here, here and here but none have worked so far.
NB the persistence is being handled by a class which looks like this:
@org.springframework.stereotype.Repository
public interface DoodahRepository extends CrudRepository<Doodah, UUID> ;
The DDL for the table is like this:
CREATE TABLE DOODAHS(id UUID not null, fieldA VARCHAR(10), fieldB VARCHAR(10));
Update
Thanks to Sve Kamenska, with whose help I finally got it working eventually. I ditched the JPA approach - and note that we are using R2DBC, not JDBC, so the answer didn't work straight away. Several sources (here, here, here, here, here and here) indicate that there is no auto Id generation for R2DBC. So you have to add a callback Bean to set your Id
manually.
I updated the class as follows:
@Table("doodahs")
public class Doodah {
@org.springframework.data.annotation.Id
private UUID id;
I also added a Bean as follows:
@Bean
BeforeConvertCallback<Doodah> beforeConvertCallback() {
return (d, row, table) -> {
if (d.getId() == null){
d.id = UUID.randomUUID();
}
return Mono.just(d);
};
}
When a new object (with id = null
, and isNew = true
) is passed to the save()
method, the callback method is invoked, and it sets the id.
Initially I tried using BeforeSaveCallback
but it was being called too late in the process, resulting in the following exception:
JdbcSQLIntegrityConstraintViolationException: NULL not allowed for column "ID"....