Автор оригинала: Vlad Mihalcea.
Вступление
В этой статье я собираюсь объяснить, как работает аннотация формулы соединения Hibernate и как вы можете использовать ее для сопоставления последнего дочернего элемента родительской сущности.
Как ранее объяснялось , @JoinFormula является очень удивительной аннотацией, которая позволяет настраивать способ объединения сущностей за пределами JPA @JoinColumn возможностей.
Модель предметной области
Для предстоящих тестовых случаев мы будем использовать следующие объекты:
Объект Комментарий к сообщению отображается следующим образом:
@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Post post;
private String review;
@Column(name = "created_on")
@Temporal(TemporalType.TIMESTAMP)
private Date createdOn;
//Getters and setters omitted for brevity
}
Не только Комментарий к сообщению имеет @ManyToOne связь с Сообщением , но Сообщение также связано с последним Сообщением следующим образом:
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
private Long id;
private String title;
@ManyToOne(fetch = FetchType.LAZY)
@JoinFormula("""
(SELECT pc.id
FROM post_comment pc
WHERE pc.post_id = id
ORDER BY pc.created_on DESC
LIMIT 1)
"""
)
private PostComment latestComment;
//Getters and setters omitted for brevity
}
Атрибут последний комментарий связывает родительскую Публикацию сущность с последней Публикацией комментария дочерней сущностью. Аннотация @JoinFormula позволяет нам определить любой запрос SQL select, чтобы обеспечить связь между двумя сущностями.
Тестирование аннотации формулы соединения в режиме гибернации
Учитывая, что в нашей базе данных есть следующие объекты:
Post post = new Post()
.setId(1L)
.setTitle("High-Performance Java Persistence");
entityManager.persist(post);
assertNull(post.getLatestComment());
entityManager.persist(
new PostComment()
.setId(1L)
.setPost(post)
.setCreatedOn(
Timestamp.valueOf(
LocalDateTime.of(2016, 11, 2, 12, 33, 14)
)
)
.setReview("Woohoo!")
);
entityManager.persist(
new PostComment()
.setId(2L)
.setPost(post)
.setCreatedOn(
Timestamp.valueOf(
LocalDateTime.of(2016, 11, 2, 15, 45, 58)
)
)
.setReview("Finally!")
);
entityManager.persist(
new PostComment()
.setId(3L)
.setPost(post)
.setCreatedOn(
Timestamp.valueOf(
LocalDateTime.of(2017, 2, 16, 16, 10, 21)
)
)
.setReview("Awesome!")
);
Когда мы извлекаем сущность Post , мы видим, что атрибут последний комментарий работает должным образом:
Post post = entityManager.find(Post.class, 1L);
PostComment latestComment = post.getLatestComment();
assertEquals("Awesome!", latestComment.getReview());
Вывод
Как я объяснил в своей книге “Высокопроизводительная сохраняемость Java”, если вы не воспользуетесь преимуществами базового поставщика JPA или возможностями реляционной базы данных , вы потеряете множество функций.