5

我正在尝试将此 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>)
4

3 回答 3

13

好吧,我终于找到了调用 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();
}
于 2012-05-03T19:00:01.187 回答
3

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

在这里,from.get("balance")返回Path<Object>,但该方法可以接受 type 的参数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)这样更清洁且易于调试。

但是,如果您有许多实体,那么如果 JPA 提供者不生成它们,那么手动编写它们的元模型类可能会很困难。

于 2012-05-02T21:00:18.807 回答
0

编译器抱怨是因为amountis an int,而不是 an Expression,看看你是否能弄清楚如何构建Expression一个常量并使用它,你应该很好。

于 2012-04-30T21:12:53.700 回答