关于 JPA 2.0 Criteria 的一些基本问题

发布于 2024-12-09 23:11:17 字数 759 浏览 0 评论 0原文

我今天发现了 JPA 2.0 Criteria API 并且想学习它。只是浏览了一些示例并尝试动手操作。我有一个水果表,其中包含以下列:

  • id、
  • 名称、
  • 颜色、
  • 大小、
  • 味道。

常规内容:

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. 如何使用条件构建以下查询:

    选择 ID、名称、颜色,其中名称如“XY%”且颜色=“橙色”
    

    即如何:

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

  2. 另外,在获取实际数据之前先计算结果总是更好。我怎样才能先获取结果计数?

另外,有没有什么地方可以让我获得更多关于“Criteria”的示例以及几种不同类型的 SQL 查询?

I discovered JPA 2.0 Criteria API today and want to learn it. Just went through some examples and try to do a hands on. I have a table fruit with columns:

  • id,
  • name,
  • color,
  • size,
  • taste.

The regular stuff:

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. How will the following query get built using criteria:

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

    I.e. how to:

    • fetch only some columns,
    • include wild card search,
    • include AND, OR where conditions.
  2. Also, its always better to get count of the result first before fetching the actual data. How can I fetch the result count first?

Also Is there any place where I can get more examples on 'Criteria' with several different kinds of SQL queries?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我偏爱纯白色 2024-12-16 23:11:17

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

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

当结果由单独的列组成时,查询的类型参数为 Object[].class(结果将是 Object[] 的列表)。另一种可能性是使用元组。您可以构建如下所述的查询。为了清楚示例参数的类型,为谓词和参数表达式创建了中间变量。您还可以将它们内联到查询创建中。

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")));

或使用元组作为结果类型:

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")));

First, you operate to Entities, not to tables, so I will assume following mapping for Fruit:

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

When result consists of separate columns, type argument to query is Object[].class (result will be List of Object[]). Other possibility is to use Tuple. You can build query you described with following. Just for being clear about type of argument for the sake of example, intermediate variables are created for Predicates and ParameterExpressions. You can also inline those to the query creation.

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();

You can also build same query by inlining everything:

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")));

Or use Tuple as result type:

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);
}

If you go for canonical metamodel, then you need following class in same package with your fruit. It is up to you do you write it by yourself or generate with some tool (for example with org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor). First time it makes sense to write it by yourself:

@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;
}

Then you can go for strongly typed arguments and replace query in former tuple example with following:

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")));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文