0

我对Spring和Hibernate以及延迟加载有一些困难。有很多问题和答案,但不是我真正想要的。Hibernate Spring JPA只加载特定的懒惰关系

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

但是当我想查看轮胎压力时,我需要初始化tires关系。我曾经这样做过Hibernate.initialize(car.getTires())。这会为数据库生成另一个SELECT查询。现在我想改进我的数据库查询,并选择与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.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的数据,那么该方法是一样的,你可以很容易地找到好例子。

EDIT

另一个测试工作示例。只要确保您的字段名称与Spring数据的域匹配即可解决它们。

public interface CarRepository extends JpaRepository<Car, Long> { 

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

Link到文档

+0

我是否需要用'@ Table'进行注解的实体?因为我们现在不这样做,如果它不需要,它会更清洁,而不是写它。还是用于对象图?我现在就试试这个。如果这对我们有用,我会将您的答案标记为解决方案。谢谢回复! – Clemenz

+0

不能将'@ Table'省略,我只是习惯用它来定义实体。 – Vaelyr

+0

我刚刚发现'Car'类扩展了一个'Vehicle'类。所以它使用'@ Inheritance'注解。 (也是@ @ DiscriminatorValue('car')注释)。当我尝试在'Car'实体中使用命名图时,它在启动时给我一个错误。 '无法使用此ManagedType [com.example.domain.Vehicle]'上的给定名称[Tires]定位属性。但是我查询'Car'库中的'Car'表。什么会造成这种情况? – Clemenz