我正在使用Spring-boot 1.5.9并且我正在尝试使用Hibernate和JPA 2.0动态创建投影,但我正在考虑某些特定情况。
考虑以下课程:
@Entity
@Table(name = "entity")
public class Entity {
@Id
@Column(name = "entity_id", nullable = false)
private Long id;
@Column(name = "first_field", nullable = false)
private String firstField;
@Column(name = "second_field", nullable = false)
private String secondField;
@OneToMany(mappedBy = "entity", fetch = FetchType.EAGER)
@Cascade(CascadeType.ALL)
private List<NestedField> nestedField;
//getters and setters
}
还有NestedField类;
@Entity
@Table(name = "nested_field")
public class NestedField {
@Id
@Column(name = "nested_field_id", nullable = false)
private Long id;
@Column(name = "first_field", nullable = false)
private String firstField;
@ManyToOne
@JoinColumn(name = "entity_id", referencedColumnName = "entity", nullable = false)
@Cascade(CascadeType.SAVE_UPDATE)
@JsonBackReference
private Entity entity;
//getters and setters
}
下面的代码是我用来通过字符串创建类实体的投影来代表字段列表的代码(例如:“field1,field2等”):
// projection String is expected to be "field1,field2,field3,...,fieldN"
private List<T> fetchProjectionData(String projections, CriteriaBuilder criteriaBuilder, Class<T> entityClass) {
CriteriaQuery<Object> query = criteriaBuilder.createQuery(Object.class);
Root<T> root = query.from(entityClass);
List<Selection<Object>> projection = getProjectionFields(projections, root);
query.multiselect(projection.toArray(new Selection[]{}));
try {
List<Object> result = (List<Object>) entityManager.createQuery(query)
.setMaxResults(100)
.setFirstResult(0)
.getResultList();
return mapResultSet(result, projection, entityClass);
} catch (Exception e) {
System.out.println("Error.");
return null;
}
}
public List<Selection<Object>> getProjectionFields(String projections, Root<T> root) {
try {
String[] projectionFields = projections.split(",");
List<Selection<Object>> projection = new ArrayList<>();
if (!projectionFields.isEmpty()) {
for (int i = 0; i < projectionFields.length; i++) {
projection.add(root.get(projectionFields[i]));
}
}
return projection;
} catch (Exception e) {
System.out.println("Error.");
return new ArrayList<>();
}
}
// mapResultSet map the result fetched into instances of the parametrized class
我希望能够预测类实体的字段(无论是哪个字段,简单字符串或嵌套字段,或者集合)。 遗憾的是,上面的代码仅在String投影参数仅由非List字段组成或仅由List值组成时才有效。 例如:
String projection = "id,firstField"; //OK
Srting projection = "nestedField"; //OK
String projection = "firstField,nestedField"; //Fails in method .getResultList(), JPA builds a query with sintax error
有趣的是,如果nestedFields不是List,而是单个实体,比如bellow,上面的代码就可以了:
@ManyToOne
@JoinColumn(name = "nested_field_id", referencedColumnName = "nested_field_id")
@Cascade(CascadeType.SAVE_UPDATE)
private NestedField nestedField; // if nestedField was this way, the code would have worked
这是hibernate JPA抛出的异常:
2018-03-18 22:50:46.535 DEBUG 20990 --- [nio-8080-exec-1] org.hibernate.SQL : select . as col_0_0_, entity0_.first_field as col_1_0_, nestedfiel1_.nested_field_id as nested_f1_2_, nestedfiel1_.first_field as first_fi2_2_, nestedfiel1_.entity_id as entity_i3_2_ from entity entity0_ inner join nested_field nestedfiel1_ on entity0_.entity_id=nestedfiel1_.entity_id limit ? 2018-03-18 22:50:46.545 WARN 20990 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 42601 2018-03-18 22:50:46.545 ERROR 20990 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: syntax error at or near "."
看来,hibernate JPA用空字符串替换我的投影,导致单个丢失的点“。”,这当然会导致错误,尽管查询几乎是正确的(如果删除丢失的点“。”) 。
我注意到root.get(projectionFields[i])
在字段是嵌套List时返回类型PluralAttributePath
,而当字段是简单字段时返回SingleAttributePath
。我想知道这与我的问题有什么关系。
有没有人有解决这个问题的线索? 我在构建查询时做错了吗?
提前致谢!