【问题标题】:Some basic questions on Criteria from JPA 2.0JPA 2.0 中关于 Criteria 的一些基本问题
【发布时间】:2011-12-09 02:24:17
【问题描述】:

我今天发现了 JPA 2.0 Criteria API,并想学习它。刚刚浏览了一些示例并尝试动手操作。我有一个带柱子的餐桌水果:

  • 身份证,
  • 姓名,
  • 颜色,
  • 大小,
  • 味道。

常规的东西:

EntityManagerFactory emf = Persistence.createEntityManagerFactory("fruitManager");
EntityManager em = emf.createEntityManager();

//get the criteria builder
CriteriaBuilder cb = em.getCriteriaBuilder();

CriteriaQuery<Fruit> c = cb.createQuery(Fruit.class);
  1. 如何使用条件构建以下查询:

    select id, name, color where name like 'XY%' and  color='orange'
    

    即如何:

    • 只获取一些列,
    • 包括通配符搜索,
    • 包括 AND、OR where 条件。

  2. 此外,在获取实际数据之前先获取结果的计数总是更好的。如何先获取结果计数?

还有什么地方可以让我获得更多关于“标准”的示例,其中包含几种不同类型的 SQL 查询?

【问题讨论】:

    标签: hibernate jpa jpa-2.0 criteria-api


    【解决方案1】:

    首先,您对实体进行操作,而不是对表进行操作,因此我将假设 Fruit 的映射如下:

    @Entity
    public class Fruit {
        @Id int id;
        String name;
        String color;
    }
    

    当结果由单独的列组成时,查询的类型参数是 Object[].class(结果将是 List of Object[])。其他可能性是使用元组。您可以构建您使用以下描述的查询。只是为了举例说明参数的类型,中间变量是为 Predicates 和 ParameterExpressions 创建的。您还可以将它们内联到查询创建中。

    CriteriaQuery<Object[]> myquery = cb.createQuery(Object[].class);
    Root<Fruit> root = myquery.from(Fruit.class);
    
    ParameterExpression<String> nameParamExp = cb.parameter(String.class, "name");
    ParameterExpression<String> colorParamExp = cb.parameter(String.class, "color");
    
    Predicate namePredicate = cb.like(root.<String>get("name"), colorParamExp);
    Predicate colorPredicate = cb.equal(root.get("color"), nameParamExp);
    
    myquery.multiselect(root.get("id"), root.get("name"), root.get("color"))
            .where(cb.and(namePredicate, colorPredicate));
    
    TypedQuery<Object[]> someFruits = em.createQuery(myquery);
    someFruits.setParameter("name", "XY%");
    someFruits.setParameter("color", "orange");
    
    someFruits.getResultList();
    

    您还可以通过内联所有内容来构建相同的查询:

    myquery.multiselect(root.get("id"), root.get("name"), root.get("color"))
            .where(cb.and(
                    cb.like(root.<String>get("name"), "XY%"),
                    cb.equal(root.get("color"), "orange")));
    

    或者使用 Tuple 作为结果类型:

    CriteriaQuery<Tuple> myquery = cb.createQuery(Tuple.class);
    Root<Fruit> root = myquery.from(Fruit.class);
    
    myquery.select(cb.tuple(root.get("id").alias("id"),
                            root.get("name").alias("name"),
                            root.get("color").alias("color")))
           .where(cb.and(
                    cb.like(root.<String>get("name"), "XY%"),
                    cb.equal(root.get("color"), "orange")));
    
    TypedQuery<Tuple> someFruits = em.createQuery(myquery);
    
    for (Tuple t: someFruits.getResultList()) {
        //access your results by alias set in query instead of using array index
        Integer id = t.get("id", Integer.class);
        String name = t.get("name", String.class);
        String color = t.get("color", String.class);
    }
    

    如果您选择规范元模型,那么您需要在与您的水果相同的包中进行以下课程。由您自己编写还是使用某些工具生成(例如使用 org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor)取决于您。第一次自己写有意义:

    @StaticMetamodel(Fruit.class)
    public abstract class Fruit_ {
        public static volatile SingularAttribute<Fruit, Integer> id;
        public static volatile SingularAttribute<Fruit, String> color;
        public static volatile SingularAttribute<Fruit, String> name;
    }
    

    然后,您可以使用强类型参数并将以前的元组示例中的查询替换为以下内容:

    myquery.select(cb.tuple(root.get(Fruit_.id).alias("id"),
                            root.get(Fruit_.name).alias("name"),
                            root.get(Fruit_.color).alias("color")))
           .where(cb.and(
                    cb.like(root.get(Fruit_.name), "XY%"),
                    cb.equal(root.get(Fruit_.color), "orange")));
    

    【讨论】:

    • 我想补充一点,您可以使用元模型生成来进行完全类型化的查询,这是一个在构建时自动生成用于列选择的类的插件。然后cb.like(root.&lt;String&gt;get("name") 可以被cb.like(root.get(Fruit_.name), colorParamExp) 交换。我还想补充一点,设置参数是不必要的步骤,您可以简单地将 colorParamExp 替换为文字 cb.like(root.get(Fruit_.name), "orange") 或在某些情况下 `cb.like(root.get(Fruit_.name), cb.literal("orange ")) 可能需要。
    • 只有当我们的实体类不存在时才使用元模型生成插件吗??
    • 设置参数只是为了展示示例。在第二个代码块中,它是用文字完成的。使用规范元模型也是我更喜欢的方式。在学习阶段,我将从基于字符串开始,并通过引入大量中间对象来加深对参数类型的理解。下一步是编写元模型并使用它。然后生成元模型。
    • @Nikunj,不,不是。只需检查 Rasmus Franke 在他的回答中提供的链接后面的文档。
    • 谢谢!将查看文档!
    【解决方案2】:

    标准API的基础教程可以在http://download.oracle.com/javaee/6/tutorial/doc/gjivm.html找到。

    示例可以在 http://www.altuure.com/2010/09/23/jpa-criteria-api-by-samples-part-i/ 找到,也可以查看第 2 部分。

    【讨论】:

    • 谢谢!!将查看文档!
    猜你喜欢
    • 2011-04-14
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-16
    相关资源
    最近更新 更多