【发布时间】:2019-10-13 21:32:51
【问题描述】:
我在使用 Criteria API 创建查询时遇到了困难投影查询实体的属性并实例化 DTO。其中一个投影属性映射与另一个实体的一对多关系,因此它是一组依赖实体。我正在使用 fetch join 来检索集合。但我收到以下错误:
org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list
我已经尝试过使用常规连接,但在这种情况下,依赖实体集不会被填充。完全删除连接和/或提取也无济于事。
我正在使用 JPA 规范 2.0、Hibernate 4.2.21.Final、Spring Data JPA 1.10.11.RELEASE。
有人可以给我建议吗?我也会很高兴有一个工作的 JPQL。
这是我的查询实现:
@Override
public List<EntityADto> findByPartialKey1OrderByPartialKey2(String partialKey1) {
// Create query
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
final CriteriaQuery<EntityADto> criteriaQuery = criteriaBuilder.createQuery(EntityADto.class);
// Define FROM clause
final Root<EntityA> root = criteriaQuery.from(EntityA.class);
root.fetch(EntityA_.oneToManyAttribute);
// Define DTO projection
criteriaQuery
.select(criteriaBuilder.construct(
EntityADto.class,
root.get(EntityA_.id).get(EntityAId_.partialKey1),
root.get(EntityA_.id).get(EntityAId_.partialKey2),
root.get(EntityA_.stringAttribute1),
root.get(EntityA_.stringAttribute2),
root.get(EntityA_.oneToManyAttribute)))
.orderBy(criteriaBuilder.asc(root.get(EntityA_.id).get(EntityAId_.partialKey2)))
.distinct(true);
// Define WHERE clause
final ParameterExpression<String> parameterPartialKey1 = criteriaBuilder.parameter(String.class);
criteriaQuery.where(criteriaBuilder.equal(root.get(EntityA_.id).get(EntityAId_.partialKey1), parameterPartialKey1));
// Execute query
final TypedQuery<EntityADto> typedQuery = entityManager.createQuery(criteriaQuery);
typedQuery.setParameter(parameterPartialKey1, partialKey1);
return typedQuery.getResultList();
}
实体如下所示:
@Entity
@Table(name = "TABLE_A", uniqueConstraints =
@UniqueConstraint(columnNames = {
"PARTIAL_KEY_1", "STRING_ATTR_1", "STRING_ATTR_2" }))
public class EntityA {
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "partialKey1", column = @Column(name = "PARTIAL_KEY_1", nullable = false)),
@AttributeOverride(name = "partialKey2", column = @Column(name = "PARTIAL_KEY_2", nullable = false))})
private EntityAId id;
@Column(name = "STRING_ATTR_1", nullable = false)
private String stringAttribute1;
@Column(name = "STRING_ATTR_2", nullable = false)
private String stringAttribute2;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "entityA")
private Set<EntityB> entityBs;
// getters and setters omitted for brevity.
}
@Entity
@Table(name = "TABLE_2")
public class EntityB {
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "partialKey3", column = @Column(name = "PARTIAL_KEY_3", nullable = false)),
@AttributeOverride(name = "partialKey1", column = @Column(name = "PARTIAL_KEY_1", nullable = false)),
@AttributeOverride(name = "partialKey2", column = @Column(name = "PARTIAL_KEY_2", nullable = false))})
private EntityBId id;
@Column(name = "VALUE")
private String value;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({
@JoinColumn(name = "PARTIAL_KEY_1", referencedColumnName = "PARTIAL_KEY_1", nullable = false, insertable = false, updatable = false),
@JoinColumn(name = "PARTIAL_KEY_2", referencedColumnName = "PARTIAL_KEY_2", nullable = false, insertable = false, updatable = false)})
private EntityA entityA;
// getters and setters omitted for brevity.
}
最后是 DTO:
public class EntityADto implements Serializable {
private static final long serialVersionUID = -5343329086697620178L;
private String partialKey1;
private Integer partialKey2;
private String stringAttribute1;
private String stringAttribute2;
private Map<String, String> additionalAttributes;
public ProzessdatStandardDto() { }
public ProzessdatStandardDto(String partialKey1,
Integer partialKey2,
String stringAttribute1,
String stringAttribute2,
Set<EntityB> entityBs) {
this.partialKey1 = partialKey1;
this.partialKey2 = partialKey2;
this.stringAttribute1 = stringAttribute1;
this.stringAttribute2 = stringAttribute2;
final Map<String, String> entityBsConverted = new HashMap<>();
if (!CollectionUtils.isEmpty(entityBs)) {
for (EntityB entityB : entityBs) {
entityBsConverted.put(entityB.getPartialKey3(), entityB.getValue());
}
}
this.additionalAttributes = prozessdatExpansionsConverted;
}
// getters and setters omitted for brevity.
}
【问题讨论】:
-
无法通过连接进行投影。
-
@K.Nicholas 好的,你能详细说明一下吗?或者指向我说明这一点的 JPQL / Criteria API 规范?谢谢。
标签: java hibernate spring-data-jpa jpql criteria-api