Rasool Ghafari
Rasool Ghafari

Reputation: 4258

Hibernate returns null for entity property that is annotated with @Formula after saving the entity

I have simple class as you can see below:

@Entity
@Table(name = "post")
public class Post {

    @Id
    @GeneratedValue
    Long id;

    @Column(name = "title")
    String title;

    @Formula("(select current_date())")
    Date currentDate;

    @OneToMany(mappedBy = "post")
    Set<PostComment> commentList = new HashSet<>();
}

and want to update this entity in the service:

@Service
@Transactional
public class PostService {

    private final PostRepository postRepository;

    public PostService(PostRepository postRepository) {
        this.postRepository = postRepository;
    }

    @Transactional
    public Post save(Post entity) {
        Post post = postRepository.saveAndFlush(entity);
        System.out.println("current_date: " + post.getCurrentDate());
        post.getCommentList().forEach(pc -> System.out.println(pc.getReview()));
        return post;
    }
}

And when i check hibernate logs, it first select all fields of Post entity but when i call post.getCurrentDate() (that it annotated with @Formula) returns null:

Hibernate: select post0_.id as id1_0_0_, post0_.title as title2_0_0_, (select current_date()) as formula0_0_ from post post0_ where post0_.id=?
Hibernate: update post set title=? where id=?
current_date: null
Hibernate: select commentlis0_.post_id as post_id3_1_0_, commentlis0_.id as id1_1_0_, commentlis0_.id as id1_1_1_, commentlis0_.post_id as post_id3_1_1_, commentlis0_.review as review2_1_1_ from post_comments commentlis0_ where commentlis0_.post_id=?
review

Why it returns and logs commentList but doesn't return currentDate? is it hibernate bug?

NOTE

I pushed the complete sample project in the github you can see here.

Upvotes: 7

Views: 4096

Answers (1)

Vlad Mihalcea
Vlad Mihalcea

Reputation: 153730

I wrote a test case on my high-performance-java-persistence GitHub repository which works like a charm.

The entity looks as follows:

@Entity(name = "Event")
@Table(name = "event")
public static class Event {

    @Id
    private Long id;

    @Formula("(SELECT current_date)")
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdOn;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Date getCreatedOn() {
        return createdOn;
    }

    public void setCreatedOn(Date createdOn) {
        this.createdOn = createdOn;
    }
}

Notice that the Date property uses the @Temporal annotation as well.

Now to emulate your use case, I wrote the following data access logic:

Event event = new Event();
event.setId(1L);

entityManager.persist(event);
entityManager.flush();

entityManager.refresh(event);

assertNotNull(event.getCreatedOn());

Notice the refresh call which is needed since the entity is cached upon persist, and we want to refetch it anew from the DB.

And, when executing it, Hibernate generates the following statements:

Query:["insert into event (id) values (?)"], Params:[(1)]
Query:["select formulacur0_.id as id1_0_0_, (SELECT current_date) as formula0_0_ from event formulacur0_ where formulacur0_.id=?"], Params:[(1)]

And the test case runs just fine. Just do a comparison debug between your use case and mine and see why yours doesn't work and mine does.

Upvotes: 4

Related Questions