Не ожидается N + 1 запросов с Hibernate Projection - PullRequest
2 голосов
/ 03 ноября 2019

Просто столкнитесь с проблемой N + 1 запросов с таким репозиторием Spring Data

public interface ToDoRepository extends CrudRepository<ToDo, Long> {

    @Query("select new com.package.repr.ToDoRepr(t) from ToDo t " +
            "where t.user.id = :userId")
    List<ToDoRepr> findToDosByUserId(@Param("userId") Long userId);
}

Я вижу в журналах один такой запрос

Hibernate: выберите todo0_.id как col_0_0_ из todos todo0_где todo0_.user_id =? ]

1007 * И N такие запросы 1009 * Hibernate: выберите todo0_.id в id1_0_0_, todo0_.description в descript2_0_0_, todo0_.target_date как target_d3_0_0_, todo0_.user_id как user_id4_0_0_, user1_.id как id1_1_1_,user1_.password в качестве password2_1_1_, user1_.username в качестве username3_1_1_ из todos todo0_ оставил внешних пользователей присоединения user1_ todo0_.user_id = user1_.id где todo0_.id =?

ToDoRepr - простой POJO. С конструктором, который принимает сущность ToDo в качестве параметра.

Вот две сущности JPA, которые я использую в этом запросе

@Entity
@Table(name = "todos")
public class ToDo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String description;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    @Column
    private LocalDate targetDate;

    // geters, setters, etc.
}
@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true, nullable = false)
    private String username;

    @Column(nullable = false)
    private String password;

    @OneToMany(
            mappedBy = "user",
            cascade = CascadeType.ALL,
            orphanRemoval = true
    )
    private List<ToDo> todos;

    // geters, setters, etc.
}

UPD. Возможно решить проблему с помощью этого запроса, но почему он не работает с конструктором, который принимает сущность в качестве параметра?

public interface ToDoRepository extends CrudRepository<ToDo, Long> {

    @Query("select new com.package.repr.ToDoRepr(t.id, t.description, t.user.username, t.targetDate) " +
            "from ToDo t " +
            "where t.user.id = :userId")
    List<ToDoRepr> findToDosByUserId(@Param("userId") Long userId);
}

1 Ответ

0 голосов
/ 04 ноября 2019

Я хочу собрать здесь несколько решений по этому вопросу. Существует простое решение без явных JPQL-запросов. Spring Data JPA может обрабатывать любые POJO с правильными геттерами и сеттерами как проекцию.

Просто это прекрасно работает для меня

public interface ToDoRepository extends CrudRepository<ToDo, Long> {

    List<ToDoRepr> findToDosByUser_Id(Long userId);
}
...