提问者:小点点

Hibernate Spring JPA只加载特定的延迟关系


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

假设我有一个汽车课。带有ID名称以及与轮子的一对多关系。由于它们是 oneToMany,因此它们是默认的延迟加载,这是首选,因为当我想查看汽车名称时,我不想看到轮胎和其他东西。这适用于我的情况,使用我的存储库的默认 findOne() 方法。

但是当我想查看轮胎压力时,我需要初始化< code>tires关系。我曾经用< code > hibernate . initialize(car . gettires())来做这件事。这将为数据库生成另一个< code>SELECT查询。现在,我想改进我的数据库查询,只选择带有< code >轮胎的< code >汽车,而忽略< code >窗户和< code >门。(这在带有joins的MySQL中是可能的)。让它们急切加载的选项是毫无疑问的,因为我并不总是想要加载< code>tires关系(我在我的对象上有一些大的关系)。

我尝试了以下方法:

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

这确实提供了正确的数据。但是在分析了从存储库返回的对象之后,我注意到所有的关系都被加载了。因此,这不仅返回具有< code >轮胎关系的< code >汽车,还返回< code >门和< code >窗。下面给出了相同的输出(加载了moneToMany关系)

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

不想要的东西。我希望它只输出< code>Car对象,而不输出它所有的惰性关系。

互联网上的人还建议调用 Car.getTires().size()。这也将产生另一个 SELECT 查询。

有什么方法可以只选择加载了< code >轮胎关系的< code >汽车?没有< code>fetch = FetchType。LAZY、< code > hibernate . initialize()还是< code>size()方法?怎么可能只连接一个表呢?此外,我不使用XML进行任何配置。

谢谢


共1个答案

匿名用户

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

这样,您可以非常具体地了解查询,并且只获取业务逻辑所需的数据。您甚至可以定义子图来显示要从轮胎实体中选择的内容。这意味着您始终对所有 Tire 实体关系进行延迟获取。默认情况下,您得到的只是轮胎(根据要求),没有来自它们的其他关系。如果您还想从轮胎中获得其他任何东西,那么您唯一要做的就是在那里定义另一组图定义,并从您的存储库中引用它们,您将查询作为子图。

@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)
}

链接留档