Hibernate Spring JPA仅加载特定的懒惰关系 [英] Hibernate Spring JPA load only specific lazy relationship

查看:142
本文介绍了Hibernate Spring JPA仅加载特定的懒惰关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Spring和Hibernate和延迟加载方面遇到了一些困难。有很多问题和答案,但不是我真正想要的。



因此,让我说我有一个 Car 类。通过 id name 以及与 doors , windows wheels 。因为他们是oneToMany,他们是默认的懒加载这是首选,因为当我想查看车的名称我不想看到轮胎和东西。这适用于我的情况,使用我的仓库的默认 findOne()方法。



但是当我想要查看轮胎压力,我需要初始化轮胎关系。我用 Hibernate.initialize(car.getTires())来做到这一点。这会为数据库产生另一个 SELECT 查询。现在我想改进我的数据库查询,并且只用轮胎选择 car ,但省略 windows 。 (这可以在MySQL中使用连接)。使它们加载的选项是不成问题的,因为我并不总是希望加载轮胎关系(我的对象有一些很大的关系)。



我尝试了以下方法:

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

这确实提供了正确的数据。但是在分析了从存储库返回的对象之后,我注意到所有的关系都被加载了。因此,这不仅会返回轮胎的关系,还会返回车门 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()方法?如何加入一张桌子不可能?



谢谢!

解决方案

我总是建议使用实体图来实现这个。我将使用Spring Data给出一个例子。无论如何,总是应该使用延迟加载,所有其他关系可以使用特定的图形连接。

通过这种方式,您可以对您的查询进行非常具体的描述,只需获取业务逻辑所需的数据。您甚至可以定义子图来显示您想要从 tires 实体中选择的内容。这意味着您总是懒得抓取所有 Tire 实体关系。默认情况下,你得到的是 tyres (按要求),并且没有其他关系。如果你还想从 tyres 中找到其他的东西,那么剩下的事情就是在那里定义另一组图形定义,并从你的存储库引用它们进行查询

  @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扩展JpaRepository< Car,Long> {

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

链接到文档


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!

解决方案

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

这篇关于Hibernate Spring JPA仅加载特定的懒惰关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆