CriteriaBuilder将字段类型与不同的接口实现进行比较

时间:2015-08-03 15:31:20

标签: hibernate jpa

我正在使用CriteriaBuilder为我的系统持久单元生成查询。其中一个@Entities有一个链接一个类的字段;这个类是一个接口的实现,例如:

MyInterface的 MyClassOne实现了MyInterface MyClassTwo实现了MyInterface ... (该字段称为myInterface,类型为MyInterface)

在我的一个查询中,我需要验证此字段的类型不是特定的接口实现,例如MyClassTwo。

我在这里找到了一些主题文档: http://www.objectdb.com/java/jpa/query/jpql/path

我尝试将以下示例行调整到我的项目中:

Predicate p = cb.notEqual(e.type(), cb.literal(Country.class));

所以我这样说:

CriteriaQuery<Order> criteriaQuery = cb.createQuery(Order.class);
Root<Order> from = criteriaQuery.from(Order.class);

Predicate p = cb.notEqual(from.get("myInterface").type(), cb.literal(MyClassTwo.class)));

但是我收到错误,告诉我找不到列CLAZZ_:

org.jboss.resteasy.spi.UnhandledException:javax.persistence.PersistenceException:org.hibernate.exception.SQLGrammarException:找不到列“CLAZZ_”; SQL语句: 从订单order0 中选择order0_.pkid为pkid3073_ [...],其中order0_.isDraft =?和clazz_&lt;&gt ;?

你能指出我正确的方向去做吗?

1 个答案:

答案 0 :(得分:0)

JPQL文档中描述的方法:

Predicate p = cb.notEqual(e.type(), cb.literal(Country.class));

转换为:

where clazz_=?

但是当使用CriteriaBuilder .select(from)函数时,未定义此虚拟colomn。唯一的方法是手动构建查询以获取虚拟列“clazz_”(“1 as clazz_”);或者可以使用文档中提出的其他查询:

SELECT COUNT(e) FROM Object e WHERE TYPE(e) <> Country

无论如何,由于我不能手动编写选择(太重且使用自动生成的字段),也不能附加.select(from)查询部分,我必须找到一个解决方法。

一个选项是在java循环中获取所有记录并在之后过滤它们。 (使用分页时太贵了,因为它意味着处理孔表只是为了知道分页的最大记录数。)

第二种选择不是很漂亮,但它保持了良好的表现。它包括在表中添加“类型”字段。为了保持系统的健壮性,我们应该在类中将该字段设置为私有,并在类型字段的setter中自动设置值。 e.g:

enum MyTypes{
    MyFirstType, MySecondType
}
public interface MyInterface{}
@Entity
public class MyFisrtType implements MyInterface{}
@Entity
public class MySecondType implements MyInterface{}
@Entity
public class TableRecord{
    private String name;
    private MyInterface typedField;
    private MyTypes fieldType;

    public void setTypedField(MyInterface typedField){
        this.typedField = typedField;
        if(typedField instanceof MyFirstType)
            this.fieldType = MyTypes.MyFirstType;
        else if(typedField instanceof MySecondType)
            this.fieldType = MyTypes.MySecondType;
    }
}

现在谓词构造就像:

cb.equal(from.<MyTypes> get("fieldType"), cb.literal(MyTypes.MyFisrtType))