JPA(或 Hibernate)在标准中投射相关实体集合的方式
JPA (or Hibernate) way to project over a related entity collection in criteria
下面是一些示例实体:
@Entity
@Table(name = "assessment")
public class Assessment implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
private Long id;
@NotNull
@Column(name = "created_date", nullable = false, updatable = false)
private ZonedDateTime createdDate;
@NotNull
@Column(name = "score")
private Float score;
@ManyToOne
private BusinessUnit businessUnit;
@NotNull
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "assessment_context_type",
joinColumns = @JoinColumn(name = "assessment_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "context_type_id", referencedColumnName = "id"))
@JsonIgnore
private Set<ContextType> contextTypes = new HashSet<>();
...
}
@Entity
@Table(name = "context_type")
public class ContextType implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
private Long id;
@Column(name = "name")
private String name;
}
我想做的是获得精简版的评估
public class SlimAssessment {
public final Long id;
public final ZonedDateTime createdDate;
public final Float score;
public final Long buId;
public final Set<Long> contextTypeIds;
public SlimAssessment(Long id, ZonedDateTime createdDate, Float score, Long buId, Set<Long> contextTypeIds) {
this.id = id;
this.createdDate = createdDate;
this.score = score;
this.buId = buId;
this.contextTypeIds = contextTypeIds;
}
}
当然省略了更多内容,但我正在尝试通过 JPA 标准来做到这一点 API
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<SlimAssessment> query = builder.createQuery(SlimAssessment.class);
Root<Assessment> ra = query.from(Assessment.class);
Join<RiskAssessment, BusinessUnit> buJoin = ra.join(Assessment_.BUSINESS_UNIT);
SetJoin<Assessment, ContextType> contextTypeJoin = ra.join(Assessment_.contextTypes);
query.multiselect(
ra.get(Assessment_.ID),
ra.get(Assessment_.SCORE),
buJoin.get(BusinessUnit_.ID),
contextTypeJoin.get(ContextType_.ID)
).orderBy(builder.asc(ra.get(Assessment_.CREATED_DATE)));
但问题是它说找不到构造函数,因为它认为 contextTypeIds 只是一个 Long。如何让查询投影到集合上并获取 ID?如果我直接 SQL 这样做,我可以加入连接 table 以获取关联的 ID,并且我想限制连接的数量以尽可能快地进行此查询(对于例如,业务部门 ID 存储在评估 table 中,所以我不需要加入那里,所以也许我应该切换它?)
感谢任何帮助
正如我在 , Hibernate or Spring Data Projection only support flat results. I think this is a perfect use case for Blaze-Persistence Entity Views 中概述的那样。
我创建了库以允许在 JPA 模型和自定义接口或抽象 class 定义的模型之间轻松映射,类似于 Spring 类固醇数据投影。这个想法是您按照自己喜欢的方式定义目标结构(领域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。
您的用例的 DTO 模型与 Blaze-Persistence 实体视图类似:
@EntityView(Assessment.class)
public interface SlimAssessment {
@IdMapping
Long getId();
ZonedDateTime getCreatedDate();
Float getScore();
String getName();
@Mapping("businessUnit.id")
Long getBuId();
// You can also map just the ids if you like
// @Mapping("contextTypes.id")
// Set<Long> getContextTypeIds();
Set<ContextTypeIdView> getContextTypes();
@EntityView(ContextType.class)
interface ContextTypeIdView {
@IdMapping
Long getId();
}
}
查询就是将实体视图应用于查询,最简单的就是通过 id 进行查询。
SlimAssessment a = entityViewManager.find(entityManager, SlimAssessment.class, id);
Spring 数据集成让您几乎可以像 Spring 数据投影一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Page<SlimAssessment> findAll(Pageable pageable);
最棒的是,它只会获取实际需要的状态!
下面是一些示例实体:
@Entity
@Table(name = "assessment")
public class Assessment implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
private Long id;
@NotNull
@Column(name = "created_date", nullable = false, updatable = false)
private ZonedDateTime createdDate;
@NotNull
@Column(name = "score")
private Float score;
@ManyToOne
private BusinessUnit businessUnit;
@NotNull
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "assessment_context_type",
joinColumns = @JoinColumn(name = "assessment_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "context_type_id", referencedColumnName = "id"))
@JsonIgnore
private Set<ContextType> contextTypes = new HashSet<>();
...
}
@Entity
@Table(name = "context_type")
public class ContextType implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
private Long id;
@Column(name = "name")
private String name;
}
我想做的是获得精简版的评估
public class SlimAssessment {
public final Long id;
public final ZonedDateTime createdDate;
public final Float score;
public final Long buId;
public final Set<Long> contextTypeIds;
public SlimAssessment(Long id, ZonedDateTime createdDate, Float score, Long buId, Set<Long> contextTypeIds) {
this.id = id;
this.createdDate = createdDate;
this.score = score;
this.buId = buId;
this.contextTypeIds = contextTypeIds;
}
}
当然省略了更多内容,但我正在尝试通过 JPA 标准来做到这一点 API
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<SlimAssessment> query = builder.createQuery(SlimAssessment.class);
Root<Assessment> ra = query.from(Assessment.class);
Join<RiskAssessment, BusinessUnit> buJoin = ra.join(Assessment_.BUSINESS_UNIT);
SetJoin<Assessment, ContextType> contextTypeJoin = ra.join(Assessment_.contextTypes);
query.multiselect(
ra.get(Assessment_.ID),
ra.get(Assessment_.SCORE),
buJoin.get(BusinessUnit_.ID),
contextTypeJoin.get(ContextType_.ID)
).orderBy(builder.asc(ra.get(Assessment_.CREATED_DATE)));
但问题是它说找不到构造函数,因为它认为 contextTypeIds 只是一个 Long。如何让查询投影到集合上并获取 ID?如果我直接 SQL 这样做,我可以加入连接 table 以获取关联的 ID,并且我想限制连接的数量以尽可能快地进行此查询(对于例如,业务部门 ID 存储在评估 table 中,所以我不需要加入那里,所以也许我应该切换它?)
感谢任何帮助
正如我在
我创建了库以允许在 JPA 模型和自定义接口或抽象 class 定义的模型之间轻松映射,类似于 Spring 类固醇数据投影。这个想法是您按照自己喜欢的方式定义目标结构(领域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。
您的用例的 DTO 模型与 Blaze-Persistence 实体视图类似:
@EntityView(Assessment.class)
public interface SlimAssessment {
@IdMapping
Long getId();
ZonedDateTime getCreatedDate();
Float getScore();
String getName();
@Mapping("businessUnit.id")
Long getBuId();
// You can also map just the ids if you like
// @Mapping("contextTypes.id")
// Set<Long> getContextTypeIds();
Set<ContextTypeIdView> getContextTypes();
@EntityView(ContextType.class)
interface ContextTypeIdView {
@IdMapping
Long getId();
}
}
查询就是将实体视图应用于查询,最简单的就是通过 id 进行查询。
SlimAssessment a = entityViewManager.find(entityManager, SlimAssessment.class, id);
Spring 数据集成让您几乎可以像 Spring 数据投影一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Page<SlimAssessment> findAll(Pageable pageable);
最棒的是,它只会获取实际需要的状态!