Автор оригинала: 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 или возможностями реляционной базы данных , вы потеряете множество функций.