Hibernate Spring JPA load only specific lazy relationship

无人久伴 提交于 2019-12-12 04:31:25

问题


I have some difficulties with Spring and Hibernate and lazy loading. There are a lot of questions and answers, but not really what i am looking for.

So lets say i have a Car class. With an id, name and one to many relationships with doors, windows and wheels. As they are oneToMany, they are default lazy loaded which is preferred because when i want to view the name of the car i dont want to see the tires and stuff. This works in my case, using the default findOne() methods of my repositories.

But when i want to view the tire pressure, i need to initialize the tires relationship. I used to do that with Hibernate.initialize(car.getTires()). This produces another SELECT query for the database. Now I want to improve my database queries and select only the car with the tires but leave out the windows and doors. (Which is possible in MySQL with joins). The option to make them load eager is out of question because i dont always want to load the tires relationship (I have some big relationships on my objects).

I tried the following approach:

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

This does provide the right data. But after analyzing the object returned from the repository, i noticed all of the relationships are loaded. So this does not only return the car with the tires relationship, but also the doors and windows. The following gives me the same output (with the moneToMany relationship loaded)

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

Something that is not wanted. I expected this to output only the Car object without all its lazy relationships.

Also suggested by people on the internet is to call Car.getTires().size(). Which will also produce another SELECT query.

Is there any way to just select the Car with only the Tires relation ship loaded? Without the fetch = FetchType.LAZY, Hibernate.initialize() or size() method? How is it not possible to just join one table? Also, i do not use XML for any configuration.

Thanks!


回答1:


I would always suggest implementing this using entity graphs. I will be giving an example using Spring Data. Also lazy loading should always be used no matter what, all other relationships can be joined using specific graphs.

This way you can be very specific about your queries and ONLY fetch the data that is necessary for your business logic. You can even define sub-graphs to show what you want to select from tires entities as well. That would mean you always have lazy fetches on all Tire entity relationships. By default all you get is tires (as requested) and no other relationships from them. If you also want anything else from tires, then only thing left for you to do is define another set of graph definitions there and reference them from your repository where you make the query as sub-graphs.

@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<>();

}

And for your repository you can have a method

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

Even if you are not using Spring Data, then the approach is the same and you can easily find good examples of that.

EDIT

Another tested working example. Just make sure your field names match from the domain for Spring Data to resolve them.

public interface CarRepository extends JpaRepository<Car, Long> {

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

Link to documentation



来源:https://stackoverflow.com/questions/40932584/hibernate-spring-jpa-load-only-specific-lazy-relationship

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!