忽略加载急切的一对一休眠



我有一个ProductGroup、Product和DetailProduct,其中包含以下内容:

class ProductGroup {
@OneToMany(mappedBy = "productGroup", fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST], orphanRemoval = true)
@JsonIgnore
open var product: MutableList<Product> = mutableListOf()
}
class Product {
@ManyToOne(fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST])
@JoinColumn(name = "ID_PRODUCT_GROUP", referencedColumnName = "id")
@JsonIgnore
open var productGroup: ProductGroup? = null,
@OneToOne(fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST], mappedBy = "product", optional = false, orphanRemoval = true)
@JsonIgnore
open var detailProduct: DetailProduct? = null
}
class DetailProduct {
@OneToOne(fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST])
@MapsId("ID_PRODUCT")
@JoinColumn(name = "ID_PRODUCT", referencedColumnName = "id")
@JsonIgnore
var product: Product? = null,
@OneToOne(fetch = FetchType.LAZY, cascade = [CascadeType.ALL])
@MapsId("ID_CODE_PRODUCT")
@JoinColumn(name = "ID_CODE_PRODUCT", referencedColumnName = "id")
@JsonIgnore
var codeProduct: CodeProduct? = null
}
class CodeProduct {
//Properties
}

当我得到列表ProductGroup时,我只想得到带有DetailProduct的列表Product,而不需要CodeProduct,但它仍然调用查询getCodeProduct。似乎DetailProduct正在加载热切的CodeProduct。尽管我设置了FetchType.LAZY。这使得查询非常长。

如何修复?谢谢大家!

这只是一对一映射的工作方式。Hibernate必须将codeProduct字段初始化为某个值。由于您的映射使用主键ID_CODE_PRODUCT作为联接列,该列从不为null,Hibernate必须查询数据库以查看对象是否真的存在,这样它就可以决定是设置null还是设置代理。理论上,您可以使用@ManyToOne,这样可以避免查询,但始终设置代理。访问该代理可能会产生异常,但是当Hibernate在延迟加载期间发现对象不存在时。

我建议您在这种情况下不要使用实体,而是创建一个专用的DTO。

您可能会喜欢Blaze Persistence实体视图所提供的功能。

我创建了这个库,以便在JPA模型和自定义接口或抽象类定义模型之间进行简单的映射,比如类固醇上的Spring Data Projections。其思想是,您可以按照自己喜欢的方式定义目标结构(域模型(,并通过JPQL表达式将属性(getter(映射到实体模型。

使用Blaze Persistence实体视图,用例的DTO模型可能如下所示:

@EntityView(ProductGroup.class)
public interface ProductGroupDto {
@IdMapping
Integer getId();
List<ProductDto> getProduct();
}
@EntityView(Product.class)
public interface ProductDto {
@IdMapping
Integer getId();
DetailProductDto getDetailProduct();
}
@EntityView(DetailProduct.class)
public interface DetailProductDto {
@IdMapping
Integer getId();
String getName();
// Other fields you need form the product
}

或者,如果你想把它压平一点,比如这样:

@EntityView(ProductGroup.class)
public interface ProductGroupDto {
@IdMapping
Integer getId();
List<ProductDto> getProduct();
}
@EntityView(Product.class)
public interface ProductDto {
@IdMapping
Integer getId();
@Mapping("detailProduct.name")
String getName();
// Other fields you need form the product
}

查询是将实体视图应用于查询的问题,最简单的是按id进行查询。

ProductGroupDto a = entityViewManager.find(entityManager, ProductGroupDto.class, id);

Spring Data集成使您可以像使用Spring Data Projections一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-数据特征

您可以使用SpringData命名约定来构建查询,查询大致如下:

List<ProductGroupDto> findAll();

最新更新