Skip to content

Hibernate dirty detection fails in case entity member are initialized #2735

@holomekc

Description

@holomekc

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions