我正在使用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 ;?
你能指出我正确的方向去做吗?
答案 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))