I am using hbm2java, which is part of Hibernate Tools, to reverse engineer a database into JPA entity classes.
I run the tool via ./mvnw clean generate-sources and the entity classes are generated and saved to target/generated-sources.
In the UserAccount database table, the Created column is defined like this. Note the default value:
Created TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
When hbm2java reverse engineers that column, the default value is not included:
...
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "CREATED", nullable = false, length = 29)
public Timestamp getCreated() {
return this.created;
}
public void setCreated(Timestamp created) {
this.created = created;
}
...
As a result, a DataIntegrityViolationException is thrown when trying to save a UserAccount entity to the database:
org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value : com.example.UserAccount.created
Really hoping there is a way around this as I have quite a few database columns with default values, the most complex being:
DEFAULT 'User' + CAST(NEXT VALUE FOR SeqUserAccountUsername as VARCHAR(19))
...that just generates a string such as User13.
I'm still learning Spring Boot and Hibernate and could use some advice on the best approach to solving this problem.
My current research:
- The same question was asked back in 2007 in the Hibernate Forums but a solution was not provided.
- This documentation talks about using the "default-value" attribute to set the "Default initialization value for a field". Is that the correct approach?
At first, you need to find someone who will able to clarify how that database works. The problem is SQL column definition like
TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULLmeans following:DEFAULT, in that case DB generates value according to default expression (CURRENT_TIMESTAMPin your case)The simplest option to get exactly the same functionality/capabilities in
Hibernate, is to use JPA Callbacks, smth. like:that allows you to specify arbitrary created timestamp, and only if it is
nullHibernatewill use current time - that is exactly what DB allows you to do.Other options do something similar, but not the same, however some of them may suit you.
@CreationTimestamp:it ignores value of
this.createdand inserts current time, calculated on Java side, into DB.@Generated(GenerationTime.INSERT)it ignores value of
this.createdand delegates generation of value to DB, basically it omits corresponding column in INSERT statement (well... "generate" is not correct definition here).if you choose to use either
@CreationTimestampor@Generated(GenerationTime.INSERT)remove corresponding settervoid setCreated(Timestamp created)in order to avoid any confusion about mutability ofcreatedfield.