我正在尝试使用IdClass对实体进行多选。我无法获得作为ID的一部分映射的列。很清楚为什么我不能,因为没有标记为@Ids的列是hibernate创建的EntityType中属性的一部分,它们是IdAttributes映射的一部分。
这段代码在openJPA中运行良好,但我决定出于各种原因进行休眠。
失败的代码:
CriteriaBuilder queryBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Tuple> query = queryBuilder.createTupleQuery();
Root<ProductSearchFilter> productSearchFilterRoot = query.from(ProductSearchFilter.class);
query.multiselect(productSearchFilterRoot.get("productId").alias("productId"),
productSearchFilterRoot.get("category").alias("category"),
productSearchFilterRoot.get("name").alias("name"),
productSearchFilterRoot.get("fdaStatus").alias("fdaStatus"));
query.distinct(true);
错误:
java.lang.IllegalArgumentException: Unable to resolve attribute [productId] against path
我的映射设置:
@Table(name = "PRODUCT_SEARCH_FILTER")
@Entity()
@IdClass(ProductSearchFilterPK.class)
public class ProductSearchFilter {
private String source;
private String productId;
private String name;
private String category;
private String searchColumn;
private String fdaStatus;
@Column(name = "SOURCE", length = 11)
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
@Column(name = "PRODUCT_ID", length = 46, insertable = false, updatable = false)
@Id
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
@Column(name = "NAME", length = 510)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Column(name = "CATEGORY", length = 10)
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
@Column(name = "SEARCH_COLUMN", length = 1088, insertable = false, updatable = false)
@Id
public String getSearchColumn() {
return searchColumn;
}
public void setSearchColumn(String searchColumn) {
this.searchColumn = searchColumn;
}
@Column(name = "FDA_STATUS", insertable = false, updatable = false)
@Id
public String getFdaStatus() {
return fdaStatus;
}
public void setFdaStatus(String fdaStatus) {
this.fdaStatus = fdaStatus;
}
}
public class ProductSearchFilterPK implements Serializable {
private String productId;
private String searchColumn;
private String fdaStatus;
public String getFdaStatus() {
return fdaStatus;
}
public void setFdaStatus(String fdaStatus) {
this.fdaStatus = fdaStatus;
}
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getSearchColumn() {
return searchColumn;
}
public void setSearchColumn(String searchColumn) {
this.searchColumn = searchColumn;
}
}
答案 0 :(得分:0)
有一种解决方法,即使用规范元模型。
不幸的是,我们从productSearchFilterRoot获得的EntityModel对我们没有多大帮助,因为它 只给我们视图作为一组。所以我们不能从那里通过属性的名称立即查询IdClass的属性。 但无论如何他们都是:
//following will contain three attributes that are part of id.
Set<SingularAttribute<? super ProductSearchFilter, ?>> s = model.getIdClassAttributes();
相反,我们会选择规范的元模型。为此,我们需要一个我们可以实现的新类 我们自己,或让Hibenate这样做:
@StaticMetamodel(ProductSearchFilter.class)
public abstract class ProductSearchFilter_ {
public static volatile SingularAttribute<ProductSearchFilter, String> category;
public static volatile SingularAttribute<ProductSearchFilter, String> fdaStatus;
public static volatile SingularAttribute<ProductSearchFilter, String> source;
public static volatile SingularAttribute<ProductSearchFilter, String> name;
public static volatile SingularAttribute<ProductSearchFilter, String> searchColumn;
public static volatile SingularAttribute<ProductSearchFilter, String> productId;
}
然后我们将使用ProductSearchFilter_的字段作为参数来获取productSearchFilterRoot:
CriteriaBuilder queryBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Tuple> query = queryBuilder.createTupleQuery();
Root<ProductSearchFilter> productSearchFilterRoot = query.from(ProductSearchFilter.class);
query.multiselect(
productSearchFilterRoot.get(ProductSearchFilter_.productId).alias("productId"),
productSearchFilterRoot.get(ProductSearchFilter_.category).alias("category"),
productSearchFilterRoot.get(ProductSearchFilter_.name).alias("name"),
productSearchFilterRoot.get(ProductSearchFilter_.fdaStatus).alias("fdaStatus"));
query.distinct(true);
因为我们现在有元模型,所以我也使用它来创建名称的选择,但因为那个不是id的一部分,我们可以保留原样:
productSearchFilterRoot.get("name").alias("name"),