JPA root получить в Hibernate не работает с атрибутом IdClass - PullRequest
1 голос
/ 30 сентября 2011

Я пытаюсь сделать множественный выбор для объекта с IdClass. Я не могу получить столбец, который отображается как часть идентификатора. Понятно, почему я не могу, так как ни один из столбцов, помеченных как @Ids, не является частью атрибутов в EntityType, который создает hibernate, они являются частью карты 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

Настройка My Mapping:

@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;
}
}

1 Ответ

0 голосов
/ 30 сентября 2011

Существует обходной путь, который использует каноническую метамодель.

К сожалению, EntityModel, которую мы получаем от productSearchFilterRoot, нам мало помогает, потому что только дает нам рассматривать как набор. Таким образом, мы не можем запросить Атрибуты IdClass сразу по имени атрибута оттуда. Но они все равно есть:

//following will contain three attributes that are part of id.
Set<SingularAttribute<? super ProductSearchFilter, ?>> s = model.getIdClassAttributes();

Вместо этого мы перейдем к канонической метамодели. Для этого нам нужен один новый класс, который мы можем реализовать сами или пусть Хибенате сделает это:

@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);

Поскольку у нас теперь есть метамодель, я также использовал ее для создания выделения для имени, но поскольку он не является частью идентификатора, мы могли бы оставить его как есть:

productSearchFilterRoot.get("name").alias("name"),
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...