【问题标题】:CriteriaBuilder join / subquery with resulting IntegerCriteriaBuilder 加入/子查询与结果整数
【发布时间】:2013-05-11 15:08:54
【问题描述】:

我正在尝试使用CriteriaBuilder 创建一个查询以选择所有库存大于零的Product。股票是sum(DeliveryRow.amount) - sum(DispatchRow.amount)。两者当然只包含正确的Product

我尝试为DeliveryRowDispatchRow 创建Subquery,尽管我觉得应该使用join() 来完成。

Product { 
    (...)
}

DeliveryRow {
    @ManyToOne
    private Product product;

    private int amount;
}

DispatchRow {
    @ManyToOne
    private Product product;

    private int amount;
}

查询

在此查询中,我不确定如何处理 xxx。我尝试过创建子查询,但没有成功。

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Product> query = cb.createQuery(Product.class);
Root product = query.from(Product.class);
query.select(product);

// sum of DeliveryRow.amount where DeliveryRow.product = Product
// minus 
// sum of DispatchRow.amount where DispatchRow.product = Product
Expression stock = xxx;  

query.where(cb.gt(stock, Integer.parseInt(0)));
return em.createQuery(query).getResultList();

关于如何解决这个问题的任何建议?

【问题讨论】:

    标签: java jpa criteria-api


    【解决方案1】:

    我最近一直在研究 JPA/JPQL,研究检索实体的三种不同方法:NamedQueries、em.CreateQuery 和 CriteriaBuilder。在我看来,CriteriaBuilder 是三者中最难使用的。我建议创建一个 NamedQuery 来处理这种情况,它会更容易实现和阅读。

    使用此 JPQL 表达式,您可以检索库存大于零的所有产品:

    SELECT p.name, SUM(delRow.amount) - SUM(disRow.amount) 
    FROM Product p join p.deliveryRows delRow join p.dispatchRows disRow
    HAVING SUM(delRow.amount) - SUM(disRow.amount) > 0
    
    /* This assumes product has a Collection<DispatchRow> named dispatchRows 
       and a Collection<DeliveryRow> named deliveryRows.
    */
    

    将此作为“产品”实体中的命名查询

    //This should be concatenated or on one line
    @NamedQuery(name="Product.hasStock" 
        query="SELECT p.name, SUM(delRow.amount) - SUM(disRow.amount) 
        FROM Product p join p.deliveryRows delRow join p.dispatchRows disRow
        HAVING SUM(delRow.amount) - SUM(disRow.amount) > 0");
    

    然后使用EntityManager 执行此查询

    @PersistenceContext
    EntityManager em;
    
    public void execute(){
      List<Object[]> products = 
          em.createNamedQuery("Product.hasStock").getResultList();
    
      /* Projections return a List<Object[]> where position 1 in the object array
         corresponds with the first field in the select statement, position two
         corresponds with the second field and so on...  These can also be strongly typed
         if an object is created and the constructor is specified in JPQL statement
      */
    }
    

    我知道这是一种与使用 Criteria API 不同的方法,但在我看来 JPQL 查询要优于 Criteria API。与与 SQL 非常相似的 JPQL 语法相比,API 感觉不太简洁和直观。如果您决定采用这条路线,我创建了一个视频教程,演示了@NamedQueries,并展示了如何强输入包含投影的查询结果。可以找到here

    【讨论】:

    • 我之前使用过 NamedQueries,虽然我使用 CriteriaBuilder 因为类型安全,你不担心吗?
    • 您对类型安全的关注点是什么,Object[]?
    • 没有查询是String。说DispatchRow 的任何更改都可能导致问题?
    • @Aquillo 因此查询包含对DispatchRow 上金额字段的一个引用。所以你说如果这个列被保留或者它的类型改变了它会破坏查询吗?这怎么不会破坏通过 API 构建的标准?您需要如何使用其名称引用该字段并对其应用聚合函数将要求类型为某种形式的数字。也许我遗漏了什么,你能详细说明一下吗?
    • 好吧,使用 CriteriaBuilder(带有 MetaModel)任何严重的 IDE 在更改相关对象的任何字段时都会注意到错误。否则它仍然会在编译时显示错误。 NamedQueries 不会?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-16
    • 2018-11-22
    • 1970-01-01
    • 1970-01-01
    • 2014-03-28
    • 2011-01-23
    • 2011-02-04
    相关资源
    最近更新 更多