Hibernate Spring JPA загружает только определенные ленивые отношения

У меня есть некоторые трудности с Spring и Hibernate и ленивой загрузкой. Есть много вопросов и ответов, но не совсем то, что я ищу.

Так скажем, у меня есть Car учебный класс. С id, name и отношения один ко многим с doors, windows а также wheels, Поскольку они являются oneToMany, они загружаются по умолчанию с отложенной загрузкой, что является предпочтительным, потому что, когда я хочу просмотреть имя car я не хочу видеть шины и прочее. Это работает в моем случае, используя по умолчанию findOne() методы моих репозиториев.

Но когда я хочу посмотреть давление в шинах, мне нужно инициализировать tires отношения. Я делал это с Hibernate.initialize(car.getTires()), Это производит другой SELECT запрос для базы данных. Теперь я хочу улучшить свои запросы к базе данных и выбрать только car с tires но пропустите windows а также doors, (Что возможно в MySQL с объединениями). Возможность заставить их загружаться нетерпеливо исключена, потому что я не всегда хочу загружать tires отношения (у меня есть большие отношения на моих объектах).

Я попробовал следующий подход:

@Query("SELECT c FROM Car c JOIN FETCH c.tires WHERE c.id = :id")
Car findOneWithTiresLoaded(@Param("id") Long id);

Это обеспечивает правильные данные. Но после анализа объекта, возвращенного из хранилища, я заметил, что все отношения загружены. Так что это не только возвращает car с tires отношения, но и doors а также windows, Следующее дает мне тот же вывод (с загруженным отношением moneToMany)

@Query("SELECT c FROM Car c WHERE id = :id")
Car findOneWithTiresLoaded(@Param("id") Long id);

То, чего не хотел. Я ожидал, что это выведет только Car объект без всех его ленивых отношений.

Также предложено людьми в Интернете, чтобы позвонить Car.getTires().size(), Который также будет производить другой SELECT запрос.

Есть ли способ просто выбрать Car только с Tires Корабль отношения загружен? Без fetch = FetchType.LAZY, Hibernate.initialize() или же size() метод? Как невозможно просто присоединиться к одному столу? Кроме того, я не использую XML для любой конфигурации.

Спасибо!

1 ответ

Я всегда предлагал бы реализовать это с помощью графов сущностей. Я приведу пример с использованием Spring Data. Кроме того, всегда следует использовать ленивую загрузку, несмотря ни на что, все другие отношения могут быть объединены с использованием определенных графиков.

Таким образом, вы можете быть очень точными в своих запросах и получать только те данные, которые необходимы для вашей бизнес-логики. Вы даже можете определить подграфы, чтобы показать, что вы хотите выбрать из tires лица, а также. Это означает, что у вас всегда есть ленивый выбор Tire отношения сущности. По умолчанию все, что вы получаете, это tires (по запросу) и никаких других отношений с ними. Если вы также хотите что-нибудь еще от tiresтогда вам остается только определить другой набор определений графиков и сослаться на них из своего репозитория, где вы выполняете запрос как подграфы.

@Entity
@Table(name = "car")
@NamedEntityGraph(name = Car.TIRES_GRAPH, attributeNodes = @NamedAttributeNode("tires"))
public class Car {

  public static final String TIRES_GRAPH = "Car.tires";

  @OneToMany(mappedBy = "car", fetch = FetchType.LAZY}
  private Set<Tire> tires = new HashSet<>();

}

И для вашего хранилища вы можете иметь метод

@Query("SELECT c FROM Car c")
@EntityGraph(Car.TIRES_GRAPH)
Set<Car> findAllWithTires();

Даже если вы не используете Spring Data, подход такой же, и вы легко можете найти хорошие примеры этого.

РЕДАКТИРОВАТЬ

Еще один проверенный рабочий пример. Просто убедитесь, что имена ваших полей совпадают с доменом для Spring Data, чтобы разрешить их.

public interface CarRepository extends JpaRepository<Car, Long> {

  @EntityGraph(attributePaths = { "tires" })
  Set<Car> findAllWithTiresByCarId(Long id)
}

Ссылка на документацию

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