У меня проблемы с созданием запроса с помощью 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.
}