使用CriteriaBuilder时编译错误

时间:2012-04-30 20:25:10

标签: java generics jpa

我正在尝试将此JPA QL转换为条件构建器。 JBoss 6.0。

"SELECT ba FROM BankAccount ba WHERE ba.balance >= :amt ORDER BY ba.ownerName ASC"

我根据几个教程编写了这段代码。

public List<BankAccount> findWithBalance(int amount) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<BankAccount> cq = cb.createQuery(BankAccount.class);
    Root<BankAccount> from = cq.from(BankAccount.class);

    ParameterExpression<Integer> balance = cb.parameter(Integer.class);
    cq.select(from);

    Predicate predicate = cb.gt(from.get("balance"), balance);
    cq.where(predicate);

    cq.orderBy(cb.asc(from.get("ownerName")));

    TypedQuery<BankAccount> query = em.createQuery(cq);

    return query.getResultList();
}

但是,我收到了一行编译错误:

Predicate predicate = cb.gt(from.get("balance"), balance);

错误是:

The method gt(Expression<? extends Number>, Expression<? extends Number>) in the type CriteriaBuilder is not applicable for the arguments (Path<Object>, ParameterExpression<Integer>)

3 个答案:

答案 0 :(得分:11)

好吧,我终于找到了调用gt()方法的正确方法。这是完整的解决方案。在JBoss 6中经过全面测试。

public List<BankAccount> findWithBalance(int amount) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<BankAccount> cq = cb.createQuery(BankAccount.class);
    Root<BankAccount> from = cq.from(BankAccount.class);

    ParameterExpression<Integer> balance = cb.parameter(Integer.class);
    cq.select(from);

    //Here is the trick!
    Predicate predicate = cb.gt(from.<Integer> get("balance"), balance);

    cq.where(predicate);
    cq.orderBy(cb.asc(from.get("ownerName")));

    TypedQuery<BankAccount> query = em.createQuery(cq);

    query.setParameter(balance, amount);

    return query.getResultList();
}

答案 1 :(得分:3)

JPA中的类型安全功能限制了这种与不兼容类型的比较,编译器本身会引发错误。

此处,from.get("balance")会返回Path<Object>,但该方法可以接受java.lang.Number类型的参数,从而导致错误。

您可以尝试以下代码。

//--
    Metamodel metamodel = em.getMetamodel();
    EntityType<BankAccount> pClass = metamodel.entity(BankAccount.class);
    Predicate predicate = cb.gt(from.get(pClass.getSingularAttribute("balance", Integer.class)), balance);
//--

如果您正在使用Metamodel API,那么您可以通过将ClassName_.field指定为cb.gt(from.get(BankAccount_.balance), balance)来直接进行撤销,这更加清晰&amp;易于调试。

但是如果你有很多实体,那么如果JPA提供者没有生成它们,可能很难手动编写他们的Metamodel类。

答案 2 :(得分:0)

编译器抱怨,因为amountint,而不是Expression,看看你是否可以弄清楚如何构建Expression这是一个常量并使用它你应该做得很好。