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 NULL
means following:DEFAULT
, in that case DB generates value according to default expression (CURRENT_TIMESTAMP
in 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
null
Hibernate
will 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.created
and inserts current time, calculated on Java side, into DB.@Generated(GenerationTime.INSERT)
it ignores value of
this.created
and 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
@CreationTimestamp
or@Generated(GenerationTime.INSERT)
remove corresponding settervoid setCreated(Timestamp created)
in order to avoid any confusion about mutability ofcreated
field.