Hibernate Spring JPA只加载特定的懒惰关系

时间:2016-12-02 12:46:21

标签: hibernate jpa spring-data-jpa lazy-loading lazy-initialization

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

所以我假设我有一个Car课程。使用idname以及与doorswindowswheels的一对多关系。因为他们是oneToMany,他们是默认延迟加载,这是首选,因为当我想查看car的名称我不想看到轮胎和东西。这适用于我的情况,使用我的存储库的默认findOne()方法。

但是当我想查看轮胎压力时,我需要初始化tires关系。我曾经用Hibernate.initialize(car.getTires())做到这一点。这会为数据库生成另一个SELECT查询。现在,我想改进我的数据库查询,只选择car tires,但忽略windowsdoors。 (这在MySQL中可以使用连接)。让他们加载的选项是不可能的,因为我不总是想加载tires关系(我的对象上有一些很大的关系)。

我尝试了以下方法:

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

这确实提供了正确的数据。但在分析从存储库返回的对象后,我注意到所有关系都已加载。因此,这不仅会返回cartires关系,还会返回doorswindows。 以下给出了相同的输出(加载了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.LAZYHibernate.initialize()size()方法?怎么不能只加入一张桌子?此外,我不使用XML进行任何配置。

谢谢!

1 个答案:

答案 0 :(得分: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)
}

Link到文档