Polymorphic CriteriaQuery没有反比关系

时间:2011-06-21 14:39:15

标签: java inheritance jpa criteriaquery

我有以下EJB结构。不要怀疑AnimalInventory,这些类只是为了以简化的方式演示结构(更新:我修改了类名以构建更好的可理解的示例。IdTag的另一个实现可能是BarcodeId)。请注意,IdTagAnimalInventory之间没有反比关系,我们假设RfidTag.code是唯一的。我看过Retrieving Polymorphic Hibernate Objects Using a Criteria QueryHibernate polymorphic query,但这些讨论似乎没有回答我的问题。

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的{​​{1}}或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] - &gt;有关。 IdTagRfidTag只知道Animal而不是IdTag。这样的查询是否可能?

1 个答案:

答案 0 :(得分:10)

如果您使用的是EclipseLink,解决方案很简单。修改路径条件以转换为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”之间的“加入”(“过滤的笛卡尔积”)。