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)
}
Ссылка на документацию