我有一个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();