Полиморфный критерий Query без обратной связи
У меня есть следующая структура EJB. Не задумываться о Animal
а также Inventory
эти классы предназначены только для упрощенной демонстрации структуры (Обновление: я пересмотрел имена классов, чтобы построить более понятный пример. Еще одна реализация IdTag
может быть BarcodeId
). Обратите внимание, что нет обратной зависимости от IdTag
в Animal
или же Inventory
и давайте предположим, RfidTag.code
уникален Я прочитал " Получение полиморфных объектов гибернации с помощью запроса критериев" и " Полиморфный запрос Hibernate", но эти обсуждения, похоже, не отвечают на мой вопрос.
public interface ItemWithIdTag
{
IdTag getIdTag();
void setIdTag(IdTag idTag);
}
@Entity public class Animal implements ItemWithIdTag,Serializable
{
@Id @GeneratedValue(strategy=GenerationType.AUTO) private long id;
@OneToOne(cascade = CascadeType.ALL)
private IdTag idTag;
}
@Entity public class Inventory implements ItemWithIdTag,Serializable
{
@Id @GeneratedValue(strategy=GenerationType.AUTO) private long id;
@OneToOne(cascade = CascadeType.ALL)
private IdTag idTag;
}
@Entity @Table(name = "IdTag") @Inheritance(strategy= InheritanceType.JOINED)
public class IdTag implements Serializable
{
@Id @GeneratedValue(strategy=GenerationType.AUTO) private long id;
private Date created;
}
@Entity @Table(name = "RfidTag")
public class RfidTag extends IdTag implements Serializable
{
private String code;
}
Теперь я хочу запросить либо Animal
или же Inventory
для данного RfidTag.code
лайк Animal ejb = bean.fEntityWithRfidTag(Animal.class,"myRfIdCode");
public <T extends ItemWithIdTag> T fOwner(Class<T> type, String catName)
{
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(type);
Root<T> from = criteriaQuery.from(type);
Path<Object> path = from.join("idTag").get("code");
CriteriaQuery<T> select = criteriaQuery.select(from);
select.where(criteriaBuilder.equal(path, catName));
TypedQuery<T> q = em.createQuery(select);
T result = (T)q.getSingleResult();}
return result;
}
К сожалению, я получаю следующую ошибку:
javax.ejb.EJBException: java.lang.IllegalArgumentException:
Unable to resolve attribute [code] against path [null]
Я предполагаю, что это связано с наследованием IdTag
-> RfidTag
а также Animal
знает только о IdTag
а не RfidTag.code
, Возможны ли подобные запросы?
1 ответ
Если вы используете EclipseLink, решение простое. Измените критерии Path для приведения к RfIdTag:
Path<Object> path = ((Path) from.join("idTag").as(RfIdTag.class)).get("code");
Если вы используете Hibernate, замените ваш метод на:
public static <T extends ItemWithIdTag> T fOwner(Class<T> type, String catName) {
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(type);
Root<T> fromType = criteriaQuery.from(type);
Root<RfIdTag> fromRfId = criteriaQuery.from(RfIdTag.class);
Path<Object> pathCode = fromRfId.get("code");
Path<Object> pathIdTagType = fromType.get("idTag");
Path<Object> pathIdTagRfId = fromRfId.get("id");
CriteriaQuery<T> select = criteriaQuery.select(fromType);
select.where(
criteriaBuilder.equal(pathCode, catName),
criteriaBuilder.equal(pathIdTagType, pathIdTagRfId));
TypedQuery<T> q = em.createQuery(select);
return q.getSingleResult();
}
Это делает "соединение" ("фильтрованный декартово произведение") между "T" и "RfIdTag".