我在Spring和Hibernate以及延迟加载方面遇到了一些困难。有很多问题和答案,但不是我想要的。
所以我假设我有一个Car
课程。使用id
,name
以及与doors
,windows
和wheels
的一对多关系。因为他们是oneToMany,他们是默认延迟加载,这是首选,因为当我想查看car
的名称我不想看到轮胎和东西。这适用于我的情况,使用我的存储库的默认findOne()
方法。
但是当我想查看轮胎压力时,我需要初始化tires
关系。我曾经用Hibernate.initialize(car.getTires())
做到这一点。这会为数据库生成另一个SELECT
查询。现在,我想改进我的数据库查询,只选择car
tires
,但忽略windows
和doors
。 (这在MySQL中可以使用连接)。让他们加载的选项是不可能的,因为我不总是想加载tires
关系(我的对象上有一些很大的关系)。
我尝试了以下方法:
@Query("SELECT c FROM Car c JOIN FETCH c.tires WHERE c.id = :id")
Car findOneWithTiresLoaded(@Param("id") Long id);
这确实提供了正确的数据。但在分析从存储库返回的对象后,我注意到所有关系都已加载。因此,这不仅会返回car
与tires
关系,还会返回doors
和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()
方法?怎么不能只加入一张桌子?此外,我不使用XML进行任何配置。
谢谢!
答案 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到文档