在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());