【JPA】JPQL查询 -- 小结

       前几篇博客对JPA做了宏观性质的总结,也搭建成功了JSF + CDI + EJB + JPA(eclipselink)的程序。在通过JPA进行对实体查询的时候,写JPQL语句困惑到了我,于是重新总结一下。

       Part1: JPQL基本用法

一、Query查询API

EM提供的创建Query方法:

    createNamedQuery(String name)

    createNativeQuery(String sqlString)

    createNativeQuery(String sqlString, Class resultClass)

    createNativeQuery(String sqlString, String resultSetMapping)

    createQuery(String jpqlString)


二、参数设置

    List getResultList()

    Object getSingleResult();   //上述用于select语句

    int executeUpdate();       //该句用于update,delete语句

    Query setFirstResult(int startPosition)

    Query setMaxResult(int maxResult)


三、使用JPQL查询步骤:

    (1)EntityManager创建Query对象

    (2)如果包含参数,setParameter()

    (3)如果需要分页,调用Query的setFirstResult()或者setMaxResult()

    (4)如果是select语句,使用getResultList()或者getSingleResult();


四、执行查询

     P460一个demo就ok,注意返回的结果List,以及两层for循环,最终拿到值,以及内层循环中的条件,select的条件个数。

    //至此,讲解基本用法


         Part2: JPQL语法

         一、from子句的使用
        from后接实体名称,建议as 别名, from后不会跟多个实体,一般通过隐式连接或者显式连接来写实现笛卡尔积或者跨表连接。
 
         二、select子句的使用

select p.name, p from Person as p
        (1)select查询返回结果一般是List集合,如上,返回[String, Person]结果的数组形式集合(需要两层循环来解析),比如:

for(int i = 0; i < result.size(); i++)
{
   Object[] values = (Object[])result.get(i);
   System.out.println(values[0] + "-->" 
      + values[1]);
}
        或者:

for(int i = 0; i < result.size(); i++)
{
    Object[] row = (Object[])result.get(i);
    for(int j = 0; j < row.length; j++)
    {
       System.out.println(row[j]);
    }
}
        (2)特殊情况,select后只有一项(包含实体对象或属性),则查询得到的集合元素就是该实体对象或属性。

        三、查询中使用构造器

select new ClassTest(p.name, p.address) from Person as p
         如上,返回一个List集合,集合元素是ClassTest.对象(前提:ClassTest是支持以p.name, p.address作为参数的构造器),如果p.name类型为:String; p.address类型为String,则ClassTest有如下构造器

ClassTest(String s1, String s2)
        

        四、使用distince排除相同的记录
            select之后跟distinct,在对实体查询时,通过distinct修饰,就可以去除重复的查询结果,语句不予展示。

       

       五、where子句和条件表达式
      (1)常用运算符:数学、二进制比较、逻辑、in\not in\ between\ is null \ is empty \ is not empty \ member of \ mot member of 。
      (2)like操作符:

select name from Person where name like 'tom%'

        上面的运算符的功能大致上和SQL语句中类似的运算符功能相同,可以将SQL中的经验直接用到JPQL当中。


        六、使用JPQL函数
        对于JPQL的掌握,一定要向SQL语句那样, 同时掌握丰富的函数,来帮助我们处理问题。

        常用函数:

       (1)字符串函数

         concat(str1,str2)\ substring(str,pos,len)\ trim([leading|trailing|both] sub from str) 

       (2)数学函数

         abs(math_expression)

 sqrt(math_express)

         mod(number,div)

         size(collection_expression)

       (3)日期、时间函数

         current_date\current_time\current_timestamp


       七、多态查询

        例如如下语句:

select p.name from Person p
        该查询不仅会查询Person全部实例的name属性,还会将Person的子类实例的name属性全部查询出来。

        当有继承关系的实体,查询父实体的属性时,会把子实体的name属性查出来。


        八、关联和连接

        参考Part3.


        九、使用orderby进行结果排序

select p from Person as p order by p.name, p.age


         十、JPQL查询的聚集函数

         JPQL支持在选出的属性上使用聚集函数,有如下5个:

          avg:属性平均值。

          count:统计选择对象的数量。

          max:统计属性值的最大值。

          min:统计属性值的最小值。

          sum:计算属性值的总和。


        十一、使用子查询

         通常用在where子句中过滤查询结果集,如果底层数据库支持子查询,则可以在JPQL语句中使用子查询,通过英文()括起来。如下:

select fatcat from Cat as fatcat
	where fatcat.weight > (select avg(cat.weight) from DomesticCat cat)
          如果JPQL子查询返回多行结果集,则需要使用in、exists、any、all等关键字,其中any、all或者some可以和>、<、=等比较运算符结合使用。

        十二、命名查询

         JPA支持使用Annotation来定义JPQL查询语句,在Annotation中定义JPQL查询语句的方式就是命名查询。JPA提供了@NamedQuery、@NamedQueries两个Annotation来定义命名查询。比如,最近做的duke-bookstore项目中就有这样的使用方法:

@Entity
@Table(name = "WEB_BOOKSTORE_BOOKS")
@NamedQuery(
        name = "findBooks",
        query = "SELECT b FROM Book b ORDER BY b.bookId")
public class Book implements Serializable {

    private static final long serialVersionUID = -4146681491856848089L;
    @Id
    @NotNull
    private String bookId;
    private String surname;
    private String firstname;
    private String title;
    private Double price;
    private Boolean onsale;
    private Integer calendarYear;
    private String description;
    private Integer inventory;

    public Book() {
    }

    public Book(String bookId, String surname, String firstname, String title,
            Double price, Boolean onsale, Integer calendarYear,
            String description, Integer inventory) {
        this.bookId = bookId;
        this.surname = surname;
        this.firstname = firstname;
        this.title = title;
        this.price = price;
        this.onsale = onsale;
        this.calendarYear = calendarYear;
        this.description = description;
        this.inventory = inventory;
    }
}
        在Entity层直接使用@NameQuery定义一个查询语句,之后在ServiceImpl层的调用如下:

public List getBooks() throws BooksNotFoundException {
    try {
        return (List) em.createNamedQuery("findBooks").getResultList();
    } catch (Exception ex) {
        throw new BooksNotFoundException(
                "Could not get books: " + ex.getMessage());
    }
}
         通过em.createNameQuery(" findBooks").getResultList(); 即可实现对@NameQuery的调用。

 

       十三、批量更新和批量删除

      (1)批量更新:

update  set ... [Where where_conditions]
         如上所示,即实现了批量更新的写法格式。


       (2)批量删除:

delete from  [where where_conditions]
         实现批量删除的基本语法,和SQL语法很像, 不做过多介绍。


    Part3:JPQL关于one to one、one to many、many to many

       概念:

     (1)关系维护端:负责对关系做CRUD操作;负责外键纪录的更新,关系被维护端没有权力更新外键纪录。 (one to many多的一方,many to many则为中间关联表)
     (2)关系被维护端:拥有MappedBy注解,不进行CRUD操作,不维护关系。

     (3)分类:  one to one、one to many、many to many  ||  单向、双向


       细致分析:

       请参考我的下一篇博客关于JPQL实体映射详细分析。


      总结:

      针对JPQL,从上面三个角度做了最初的总结,后面遇到问题的解答以及详细介绍仍在继续。




你可能感兴趣的:(【Developing,EJB,Applications】)