-
-
Notifications
You must be signed in to change notification settings - Fork 102
Description
Hi guys,
we detected the following issue. As soon as our entity contains an initialized field like this one:
@Entity
public class Fruit implements Serializable {
@Id
private int id;
private String name = "Banana";
}The dirty detection is not running as expected. Just fetching a persisted Fruit entity results in an update without any change:
@GET
@Produces(MediaType.TEXT_PLAIN)
public Uni<String> getFruit() {
return repository.findById(0) //
.onItem().transform(Fruit::getName);
}Reproducer
We created a reproducer here:
https://github.com/holomekc/hibernate-init-reproducer
Expected behavior
Running the FruitResourceTest results in an insert followed by a single select statement
Actual behavior
Running the FruitResourceTest results in an insert followed by a select statement, which is then followed by an update statement without the entity being touched.
Example logs
2025-11-04 13:52:18,722 TRACE [org.hib.orm.jdb.bind] (vert.x-eventloop-thread-1) binding parameter (1:VARCHAR) <- [Apple]
2025-11-04 13:52:18,722 TRACE [org.hib.orm.jdb.bind] (vert.x-eventloop-thread-1) binding parameter (2:INTEGER) <- [0]
[Hibernate]
insert
into
Fruit
(name, id)
values
($1, $2)
2025-11-04 13:52:18,794 TRACE [org.hib.orm.jdb.bind] (vert.x-eventloop-thread-2) binding parameter (1:INTEGER) <- [0]
[Hibernate]
select
f1_0.id,
f1_0.name
from
Fruit f1_0
where
f1_0.id=$1
2025-11-04 13:52:18,805 TRACE [org.hib.orm.jdb.bind] (vert.x-eventloop-thread-2) binding parameter (1:VARCHAR) <- [Apple]
2025-11-04 13:52:18,806 TRACE [org.hib.orm.jdb.bind] (vert.x-eventloop-thread-2) binding parameter (2:INTEGER) <- [0]
[Hibernate]
update
Fruit
set
name=$1
where
id=$2
Assumption:
Our wild assumption is that with one of the latest updates the dirty detection "starts" too early. So before the data is actually loaded from the db. So the entity name is set to "Banana" and then overwritten by the value from the db which is "Apple" and this is already detected as a change on the entity.
The purpose of the initialized value is to define default values, which are also valid for java code. E.g. we used this in the past to define the first status model value like STARTED etc.
Workaround
Our current workaround, which is a bit ugly and verbose, looks like this:
@Entity
public class Fruit implements Serializable {
@Id
private int id;
@ColumnDefault("Banana")
private String name;
public String getName() {
if(name == null) {
return "Banana";
}
return name;
}
}Setup
Versions with issue
Quarkus: 3.29.0
Hibernate Reactive: 3.1.5.Final
Hibernate Orm: 7.1.4.Final
Latest known working versions
Quarkus: 3.25.3
Hibernate Reactive: 3.0.6.Final
Hibernate Orm: 7.0.8.Final