【问题标题】:Hibernate returns null for entity property that is annotated with @Formula after saving the entity保存实体后,Hibernate 为使用 @Formula 注释的实体属性返回 null
【发布时间】:2018-06-24 10:10:18
【问题描述】:

我有一个简单的类,如下所示:

@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<>();
}

并希望在服务中更新此实体:

@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;
    }
}

当我检查休眠日志时,它首先selectPost 实体的所有字段,但是当我调用post.getCurrentDate()(它用@Formula 注释)返回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

为什么它返回并记录commentList 但不返回currentDate?是休眠错误吗?

注意

我将完整的示例项目推送到了github中你可以看到here

【问题讨论】:

    标签: java hibernate jpa transactions formula


    【解决方案1】:

    我写了a test case on my high-performance-java-persistence GitHub repository,它就像一个魅力。

    实体如下所示:

    @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;
        }
    }
    

    注意Date 属性也使用@Temporal 注释。

    现在为了模拟您的用例,我编写了以下数据访问逻辑:

    Event event = new Event();
    event.setId(1L);
    
    entityManager.persist(event);
    entityManager.flush();
    
    entityManager.refresh(event);
    
    assertNotNull(event.getCreatedOn());
    

    注意refresh 调用,因为实体缓存在persist 上,因此我们希望从数据库中重新获取它。

    并且,在执行时,Hibernate 会生成以下语句:

    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)]
    

    并且测试用例运行得很好。只需在您的用例和我的用例之间进行比较调试,看看为什么您的用例不起作用而我的用例起作用。

    【讨论】:

    • 如果你检查休眠日志,它会选择所有列,还有select current_date(),但为什么不设置为currentDate字段?
    • @Generated 用于计算和保存列的值,但我只想在加载对象时进行计算。我应该调试什么?
    • 在调试模式下运行查询并检查 JDBC ResultSet 包含的内容。
    • 这是查询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=?的结果,它选择所有列
    • 我更新了我的答案,参考了 GitHub 上的一个测试用例,它工作得很好。
    猜你喜欢
    • 2016-09-17
    • 1970-01-01
    • 2020-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多