Почему нам нужно использовать граф сущностей?

Я склонялся JPA и я обнаружил, что мы можем использовать граф сущности, так как JPA 2.1.

Но я еще не понял достоинства графа сущностей.

Я знаю, что одним из достоинств использования графа сущностей является то, что мы можем указывать только те данные, которые мы хотим получить среди всей сущности, но в случае, если мы хотим целую сущность, есть ли какая-либо другая причина использовать граф сущностей? или мы должны использовать граф сущностей только тогда, когда мы хотим получить частичные данные?

если есть другой смысл или цель, когда мы используем граф сущностей, я хотел бы знать это.

2 ответа

JPA Entity Graph позволяет переопределить план выборки по умолчанию.

План выборки по умолчанию

Как я объяснил в этой статье , каждая сущность имеет план выборки по умолчанию, который определяется во время сопоставления сущностей и указывает Hibernate, как извлекать ассоциации сущностей.

По умолчанию и ассоциации используют стратегию FetchTyp.EAGER, что является ужасным выбором с точки зрения производительности. По этой причине рекомендуется устанавливать все @ManyToOne и @OneToOne ассоциации использовать FetchType.LAZY стратегия, как в следующем примере:

      @Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {

    @Id
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    private Post post;

    private String review;
    
    //Getters and setters omitted for brevity
}

При получении объекта с помощью метода:

      PostComment comment = entityManager.find(PostComment.class, 1L);

Hibernate выполняет следующий SQL-запрос:

      SELECT pc.id AS id1_1_0_,
       pc.post_id AS post_id3_1_0_,
       pc.review AS review2_1_0_
FROM post_comment pc
WHERE pc.id = 1

Связь выбирается как прокси , у которого есть только id установлен post_id Столбец внешнего ключа, загруженный вышеупомянутым SQL-запросом.

При доступе к любому свойству прокси, не являющемуся идентификатором:

      LOGGER.info("The comment post title is '{}'", comment.getPost().getTitle());

Выполняется вторичный SQL-запрос, извлекающий Post организация по запросу:

      SELECT p.id AS id1_0_0_,
       p.title AS title2_0_0_
FROM post p
WHERE p.id = 1

-- The comment post title is 'High-Performance Java Persistence, part 1'

Отмена плана выборки по умолчанию

Если мы хотим переопределить план выборки по умолчанию и быстро получить ассоциацию во время выполнения запроса, мы можем использовать запрос JPQL, который инструктирует Hibernate получить ленивую ассоциацию с помощью предложения FETCH JOIN:

      PostComment comment = entityManager.createQuery("""
    select pc
    from PostComment pc
    left join fetch pc.post
    where pc.id = :id
    """, PostComment.class)
.setParameter("id", 1L)
.getSingleResult();

LOGGER.info("The comment post title is '{}'", comment.getPost().getTitle());

Затем план выборки по умолчанию будет переопределен, и ассоциация будет загружена с нетерпением:

      SELECT pc.id AS id1_1_0_,
       p.id AS id1_0_1_,
       pc.post_id AS post_id3_1_0_,
       pc.review AS review2_1_0_,
       p.title AS title2_0_1_
FROM post_comment pc
LEFT JOIN post p ON pc.post_id = p.id
WHERE pc.id = 1

Декларативный график сущностей JPA

План выборки по умолчанию также можно переопределить с помощью графа сущностей JPA. Например, мы могли бы определить конкретный план выборки, используя следующую аннотацию JPA:

      @Entity(name = "PostComment")
@Table(name = "post_comment")
@NamedEntityGraph(
    name = "PostComment.post",
    attributeNodes = @NamedAttributeNode("post")
)
public class PostComment {
    //Code omitted for brevity
}

С PostComment.post EntityGraph готов, теперь мы можем загрузить PostComment сущность вместе с связанной с ней post сущность, например:

      PostComment comment = entityManager.find(
    PostComment.class, 
    1L,
    Collections.singletonMap(
        "javax.persistence.loadgraph",
        entityManager.getEntityGraph("PostComment.post")
    )
);

И при выполнении вышеуказанного find , Hibernate генерирует следующий запрос SQL SELECT:

      SELECT pc.id AS id1_1_0_,
       pc.post_id AS post_id3_1_0_,
       pc.review AS review2_1_0_,
       p.id AS id1_0_1_,
       p.title AS title2_0_1_
FROM post_comment pc
LEFT OUTER JOIN post p ON pc.post_id = p.id
WHERE pc.id = 1

Если вы используете Spring, вы можете ссылаться на JPA EntityGraph в методе репозитория, используя @EntityGraph аннотация:

      @Repository
public interface PostCommentRepository 
        extends CrudRepository<PostComment, Long> {

    @EntityGraph(
        value = "PostComment.post", 
        type = EntityGraphType.LOAD
    )
    PostComment findById(Long id);
}

Программный график сущностей JPA

Если вам не нравятся аннотации, вы также можете программно построить JPA EntityGraph, используя createEntityGraph метод JPA EntityManager, как показано в следующем примере:

      EntityGraph<PostComment> postCommentGraph = entityManager
    .createEntityGraph(PostComment.class);
    
postCommentGraph.addAttributeNodes("post");

PostComment comment = entityManager.find(
    PostComment.class, 
    1L,
    Collections.singletonMap(
        "javax.persistence.loadgraph",
        postCommentGraph
    )
);
  1. В Jpa hibernate выборка сущностей с ассоциациями всегда была вопросом производительности.
    • Ленивая загрузка ассоциаций в транзакцию снова и снова приводит к проблемам выбора n+1, и для избежания таких проблем используются JPQL join fetch и Cr iteria api объединения. Но выборка данных с этими двумя также приводит к проблемам перекрестного соединения, что означает, что перекрестное объединение всех записей таблицы возвращается в состояние гибернации.
    • Кроме того, изменение переменной выборки, определенной в аннотациях на уровне объекта, также не является хорошим вариантом для варианта использования.
    • Следовательно, для решения вышеупомянутых двух проблем были введены графы сущностей. Все узлы, определенные в графе сущностей, всегда извлекаются с нетерпением, независимо от их определения на уровне сущности. Эти графики передаются как подсказка для запросов.
    • Передавая графы в качестве подсказки, решаются проблемы перекрестного объединения, а также можно изменить поведение аннотации, заданное уровнем извлечения ассоциации.

Для кода вы можете проверить мой репозиторий GitHub:

https://github.com/vaneetkataria/Jpa-Hibernate/blob/master/jdbcToJpaMigration/src/test/java/com/katariasoft/technologies/jpaHibernate/entity/fetch/entitygraph/dynamic/MultiInstructorsDynamicEntityGrpahTests.java

Другие вопросы по тегам