在JPA和Hibernate中使用Java 8 Optional

  Java 8引入了java.util.Optional 这样容器对象,可以包含或不包含值,结合Optional和Stream是非常方便,可以将某些实体属性是空的值表达为Optional。

假设下面实体模型:

Post实体是我们的实体聚合,有多个PostComment关联,每个PostComment有一个Attachment,Attachment可使用Optional来表达。

java.util.Optional并不实现Serializable,因此,我们不能映射实体属性作为Optional,因为这样会限制实体的使用。比如:假如detached实例需要保存在HttpSession,每个保存在HttpSession的对象都应该是Serializable,这样在集群下会话中对象能够跨节点复制,而能够被网络复制的对象都应该是Serializable。

虽然字段属性不能直接使用Optional,但是get/set方法是可以使用的。

@Entity(name = "PostComment")
@Table(name = "post_comment")
public static class PostComment
    implements Serializable {
 
    @Id
    @GeneratedValue
    private Long id;
 
    private String review;
 
    @ManyToOne(fetch = FetchType.LAZY)
    private Post post;
 
    @ManyToOne(fetch = FetchType.LAZY)
    private Attachment attachment;
 
    public Optional<Attachment> getAttachment() {
        return Optional.ofNullable(attachment);
    }
 
    public void setAttachment(Attachment attachment) {
        this.attachment = attachment;
    }
     
    //Other getters and setters omitted for brevity
}

下面是测试:

使用:

byte[] coverContent = new byte[] {1, 2, 3};
 
Post post = new Post();
post.setId(1L);
post.setTitle("High-Performance Java Persistence");
entityManager.persist(post);
 
PostComment comment1 = new PostComment();
comment1.setPost(post);
 
entityManager.persist(comment1);
 
Attachment cover = new Attachment();
cover.setContent(coverContent);
entityManager.persist(cover);
 
PostComment comment2 = new PostComment();
comment2.setPost(post);
comment2.setAttachment(cover);
 
entityManager.persist(comment2);

假设有一个PostComment集合list:

List<PostComment> comments = entityManager.createQuery(
    "select pc " +
    "from PostComment pc " +
    "join pc.post p " +
    "where p.id = :postId", PostComment.class)
.setParameter("postId", 1L)
.getResultList();

能如下处理Attachment(s):

Attachment notAvailable = getNotAvaillableImage();
 
List<Attachment> attachments = comments
.stream()
.map(pc -> pc.getAttachment()
.orElse(notAvailable))
.collect(Collectors.toList());

 

Hibernate专题