I'm trying to save an entity with multiple fields generated by DB triggers.
public class MyEntity {
@Id
@GeneratedValue
protected UUID id;
//generated by DB trigger
@Generated(value = GenerationTime.ALWAYS)
@Column(name = "generated_number", insertable = false, updatable = false)
private String generatedNumber;
//generated by DB trigger
@Generated(value = GenerationTime.INSERT)
@Column(name = "postfix", insertable = false, updatable = false)
private Integer postfix;
//other normal fields
}
@Repository
public interface MyRepository extends PagingAndSortingRepository<MyEntity, UUID>, JpaRepository<MyEntity, UUID>
Documentation states that Generated annotation marks fields as filled by DB. Hibernate ought to load generated data from DB.
Generated properties are properties that have their values generated by the database. Typically, Hibernate applications needed to refresh objects that contain any properties for which the database was generating values. Marking properties as generated, however, lets the application delegate this responsibility to Hibernate. When Hibernate issues an SQL INSERT or UPDATE for an entity that has defined generated properties, it immediately issues a select to retrieve the generated values.
Properties marked as generated must additionally be non-insertable and non-updateable. Only @Version and @Basic types can be marked as generated.
However, the content of generated fields is not loaded until flush.
@Transactional
public MyEntity save(MyEntity entity) {
//save without flush
//assertions fail
//MyEntity updated = repository.save(entity);
//works fine
MyEntity updated = repository.saveAndFlush(entity);
assert updated.getGeneratedNumber() != null;
assert updated.getPostfix() != null;
}
My generated fields are marked as non-insertable and non-updatable. They are of a basic String type. I also tried adding a @Basic
annotation above them, but it wasn't helpful.
What am I missing?
Usually because of caching, call to the database is performed actually when the transaction finishes. You are using @Transactional
attribute, so that call is performed at the end of the method exactly by flush()
, more specifically done internally by commit()
. That is why you don't see the changes in code and the values are not generated - the call to the db was not done, before flush()
.