EJB3.0笔记-9实体查询与EJB QL

本文介绍了在 Java Persistence 中如何同时使用 EJBQL 查询语言和原生 SQL 来完成查询操作。重点阐述了 EJBQL 的特点、参数设置、日期型参数处理、结果分页、查询提示、刷新模式、构造函数表达式、IN 操作符、LEFT JOIN、FetchJoins、DISTINCT 关键字以及 WHERE 子句的用法。此外,还详细解释了如何使用实体映射元数据进行复杂原生查询和具名 EJBQL 或原生 SQL 查询的定义。
在java persistence中,可以同时使用EJB QL查询语言和原生的SQL来完成查询操作。由于EJB QL是一种描述Java对象的查询语言,而entity manager会为你处理由EJB QL向原生SQL转换的工作,因此它具有跨数据库厂商实现的移植能力。EJB QL比SQL更加紧凑和更容易阅读,但是EJB QL不可能都支持数据库所有私有特性,所以功能上没有厂商原生SQL那么功能全面。

Query API
    通过javax.persistence.Query接口来实现查询功能,而Query接口可以通过javax.persistence. EntityManager得到。
   
 参数
    EJB QL支持具名参数(named parameters)和指示参数(positional parameters),如:
    Query query=entityManager.createQuery(“from Customer c where c.firstName=:first and
         c.lastName=:last”);
    query.setParameter(“first”,first);
    query.setParameter(“last”,last);
    return query.getResultList();
    或者
    Query query=entityManager.createQuery(“from Customer c where c.firstName=?1 and
         c.lastName=?2”);
    query.setParameter(1,first);
    query.setParameter(2,last);
    return query.getResultList();

日期型参数
    如果要将java.util.Date或java.util.Calendar参数传入查询中,就得使用特殊的setParameter方法,    如下:
    setParameter(String name,java.util.Date value,TemporalType temporalType);
    setParameter(String name,Calendar value,TemporalType temporalType);
    其中temporalType表示将Date或Calendar参数转换成原生SQL类型时,使用的是何种数据库类型

对结果分页
    Query query=entityManager.createQuery(“from Customer c”);
    return query.setMaxResults(max).setFirstResult(index).getResultList();

Hints
    有些java.persistence厂商会为你提供一些能在执行查询时使用的附加功能,比如Jboss的EJB3.0允许    为查询定义超时。
    Query query=entityManager.createQuery(“from Customer c”);
    query.setHint(“org.hibernate.timeout”,1000);

FlushMode
    默认的flush模式,会在em查询之前,执行flush动作(把更新同步到数据库)。如果希望在查询前不执行    flush,可以通过
    Query query=entityManager.createQuery(“from Customer c”);
    query.setFlushMode(FlushModeType.COMMIT);

EJB QL
EJB QL是按照实体的抽象持久结构来表达的,包括:抽象结构名称、基本成员属性和关系型成员属性。抽象结构名,默认是非限定类名,如果使用了
@Entity(name=”Cust”)
public class Customer{….}
那么查询Customer 的EJB QL为 select c from Cust AS c;

简单查询
    select object(c) from Customer as c 等价于select c from Customer as c

选择实体和关系型成员属性
    对于
    @Entity
    public class Customer{
        private int id;
        private String first;
        private Address address;
        @Id
        public int getId(){…..}
        public getFirstName(){return first;}
        …………
    }
    选择成员属性可以使用:
    select c.firstName from Customer as c;或者
    select c.first from Customer as c;
    选择关联的实体可以使用:
    select c.address from Customer as c;
    选择关联实体的属性可以使用:
    select c.address.city  from Customer as c;
    但是如果Address不是持久型成员,只是普通的class,上面的语句是非法的。可以使用
    @Embedded private Address address;让语句变回合法。

构造函数表达式
    可以在select子句是指定一个构造函数,用于创建普通的JAVA对象(而非实体),如:
    select new com.tian.domain.Name(c.firstName,c.lastName) from Customer c;

IN操作符和INNER JOIN
    返回所有乘客的所有预订信息
    select r from Customer as c ,in(c.reservations) r;
    等效于
    select r from Customer as c inner join c.reservations r;//inner可以省略

LEFT JOIN
    查询所有顾客及他们的电话号码,如果顾客没有电话号码以null代替
    select c.firstName ,p.number from Customer c left join c.phoneNumbers p;
    //left join可以写成left outer join

Fetch Joins
如果关系型成员属性FetchType在定义XML时(或注解)设为LAZY,那么在程序访问到这些成员时才从数据库加载数据,有时会增加数据库访问量,可以通过JOIN FETCH强制加载这些关系成员,如:
select c from customer c left join fetch c.phones;这时会提前加载Phone关联

使用DISTINCT
关键字distinct确保查询不会返回重复项。如查询所有预订舱位的顾客,由于顾客可以预订多次,所有distinct可以派上用场。
select distinct cust from Reservation as res, in (res.customers) cust;

where 子句与字面常量
where 子句用于缩小选择范围。如果使用到字符串常量,可以使用单引号括起来,如果字符串中又有一个单引号,请用两个单引号表示;如果是数值型的常量,就直接书写;如果是布尔型,常量取值用true和false。如
where name=’capital one’; where name=’wendy’’s’;where hasGoodCredit=true;
如果不想涉及这些细节,可以直接使用查询参数,让查询API处理这些问题

where 子句与运算符的优先级
点号(.)à数学运算符(+-*/)à比较运算符(=,>,like,between,in,is null,is empty,member of)à逻辑运算符(not,and or)

where子句与数学运算符
允许查询操作在做比较时执行算术运算。运算过程中,数值也许被放宽或提升,如int 与double相乘,先把int 变成double,结果也是double的

where子句和逻辑运算符

and 和or运算符的行为与java语言中的&&和||有所不同。&&只有左操作数为true时才会对右操作数求值,and要由转换出的原生语言决定

where 子句和in

    IN用来检验是否与一组字面常量中的元素相匹配,如:
    where c.address.state IN(‘FL’,’TX’,’WI’);
    也可以使用参数
    where c.address.state IN(?1,?2,?3,5.7);
where 子句与is null
    比较运算符is null允许检验路径表达式是否为null。它也可以用来检验输入参数,如
    select c from Customer as c
    where :city is not null and :state is not null
    and c.address.state=:state

where 子句与is empty

is empty检验集合类型的关系是否为空(没有元素),集体类型的关系是从不会为null的。对from子句已经被赋予标识符的集合型关系使用is empty是非法的,如:
select r from Reservation as r inner join r.customers as c //已经赋予标识符c,表明c一定不为空
where r.customers is not empty;

where 子句与member of

member of用于判断某个实体是否是集合型关系的一个成员,如
where cust not member of  res.customers

where子句与like

可以使用两个特殊的字符“%”(表示任意字符序列)和“_”(表示单个字符),如果字符串本来就有%或_,可以使用“\”字符来避免冲突

函数表达式
     字符串处理函数
        LOWER(String):转换成小写
        UPPER(String):转换成大家
        TRIM([[leading|trailing|both][trim_char]from)]String):去除指定字符trim_char,默认为空格
        CONCAT(String1,String2):连接字符串
        LENGTH(String):求字符串长度
        LOCATE(String1,String2[,start]):String1在String2的什么位置
        SUBSTRING(String1,sart,length):截取字符串
     数字函数
        ABS(number):绝对值
        SORT(double):平方根
        MOD(int,int):求余数
     返回日期和时间的函数
        CURRENT_DATE:返回当前日期
        CURRENT_TIME:返回当前时间
        CURRENT_TIMESTAMP:返回当前时间戳
     聚合函数
        COUNT():返回查询结果集中的条目数
        MAX():找出最大值
        MIN():找出最小值
        AVG(numeric):平均值
        SUM(numerc):求和

ORDER BY子句
对返回集合进行排序。在EJB QL中有一个使用限制:order by子句中出现的属性,必须出现在select子句中,或者是select子句选中实体的一个属性。如:
select c from Customers as c order by c.address desc;select addr.zip from Address as addr order by add.zip;
以下是非法的
select c from Customers as c order by c.address.city desc;// city不是c的直接属性
GROUP BY 与HAVING
group by 用于分组,having对分组进一步筛选。group by子句中指定的字段必须出现于查询的返回结果中,这和SQL的要求是一致的。

子查询
    子查询是内嵌于主查询的另一个查询。EJB QL支持在where和having子句中使用子查询
    查询费用超过$100,000的所有航程
    from Cruise cr where 100000<(select sum(res.amountPaid) from cr.reservations res)
    
    ALL,ANY,SOME
    如果子查询返回多项结果,可以使用ALL、ANY和SOME对结果做进一步限定
    如果子查询中的所有内容都与条件表达式相匹配,那么操作符ALL就返回true
    查询所有预付了舱位预订定金的航程
    from Cruise cr where 0< all(select res.amountPaid from cr.reservations res)
    如果子查询中的有任意一项与条件表达式相匹配,那么操作符ALL或SOME就返回true
   
    EXISTS
    如果子查询包含一项或多项结果,那么操作符EXISTS返回true

批量的UPDATE与DELETE
    给所有名叫Bill Burke的乘客增加$10
    update Reservation res set res.amountPaid=(res.amountPaid+10)
    where exists(
        select c from res.customers c
        where c.firstName=’Bill’ and c.lastName=’Burke’
    );
    是否可以写成?
    update Reservation res set res.amountPaid=(res.amountPaid+10)
    where res.customers.firstName=’Bill’ and res.customers.lastName=’Burke’

    删除所有Bill Burke的舱位预订记录
    delect from Reservation res
    where exist(
        select c from res.customers c
        where c.firstName=’Bill’ and c.lastName=’Burke’
    )

原生查询
EntityManager接口有三个创建原生查询的方法:一个返回标量值,一个返回实体类型,还有一个返回多个实体与标量值组合

标量原生查询
createNativeQuery(String sql);

简单实体的原生查询

createNativeQuery(String sql,Class entityClass);根据某个实体定义好的映射元数据,将返回值映射到该实体

复杂原生查询

createNativeQuery(String sql,String mappingName)
    返回多个实体
        @Entity
        @SqlResultSetMapping(name=”customerAndCreditCardMapping”,//映射名
                entities={@EntityResult(entityClass=Customer.class),//entities指定映射的实体
                    @EntityResult(entityClass=CreditCard.class,
           fields={@FieldResult(name=”id”,column=”CC_ID”),//指定实体内成员与返回字段的映射
                    @FieldResult(name=”number”,column=”number”)})
                        })
        public class Customer{………}
        等价XML
        <entity-mappings>
            <sel-result-set-mapping name=” customerAndCreditCardMapping”>
                <entity-result entity-class=”com.titan.domain.Customer”/>
                <entity-result entity-class=”com.titan.domain.CreditCard”>   
                    <field-result name=”id” column=”CC_ID”/>
                    <field-result name=”number” column=”number”/>
                </entity-result>
            </sel-result-set-mapping>
        </entity-mappings>
        使用方法
        String sql=”select c.id,c.firstName,cc.id As CC_IC,cc.number from CUST_TABEL
           c,CREDIT_CARD_TABLE cc….”
        manager.createNativeQuery(sql,”customerAndCreditCardMapping”);
       
   返回结果既有标量也有实体
        @SqlResultSetMapping(name=”reservationCount”,//映射名
                entities={@EntityResult(entityClass=Cruise.class,              
                        fields={@FieldResult(name=”id”,column=”id”) })},
                columns={@ColumnsResult(name=”resCount”)}//标量
                )
        @Entity
        public class Cruise{……}
        等价XML
        <entity-mappings>
            <sel-result-set-mapping name=” reservationCount”>
                <entity-result entity-class=”com.titan.domain.Cruise”>   
                    <field-result name=”id” column=”id”/>
                </entity-result>
                <column-result name=”resCount”>
            </sel-result-set-mapping>
        </entity-mappings>
        使用方法
        String sql=”select c.id,count(Resrvation.id) as resCount from Cruise c left join
             Reservation on c.id=………..”;
        manager.createNativeQuery(sql,” reservationCount”);

具名EJB QL查询
    预先定义好EJB QL或原生的SQL查询
    使用@javax.persistence.NamedQuery用来预定EJB QL的,NamedQuerys用于定义多条查询
    @NamedQuerys({
        NamedQuery(name=”getAverageReservateion”,//名字
            query=”select AVG(r.amountPaid) from Cruise As c Join c.reservatons r where
                 c=:cruise”),//EJB QL
        NamedQuery(……)
    })
    @Entity
    public class Cruise{…….}
    等价XML
    <entity-mapping>
        <named-query name=” getAverageReservateion”>
            <query>
                EJB QL
            </query>
        </ named-query >
    </entity-mapping >
    使用方式
    Query query=em.createNamedQuery(“getAverageReservateion”);
    query.setParameter(“cruise”.cruise);

具名原生查询
    使用@javax.persistence.NamedNativeQuery注解来预定义具名原生SQL查询
    @NamedNativeQuery(
        name=”findCustAndCCNum”,
        query=”select ……..”,//原生SQL
        resultClass=”…”,//只返回一个实体时用
        resultSetMapping=”….”
        //一个声明的@SqlResultSetMapping,用于返回多个实体和或实体与标量混合的查询
    )
等价XML
    <entity-mappings>
        <named-native-query name=” getAverageReservateion” result-set-mapping=”….”>
            <query>
                原生SQL
            </query>
        </ named-native-query >
    </entity-mappings >
    使用方式
    Query query=em.createNamedQuery(“getAverageReservateion”);
    query.setParameter(“cruise”.cruise);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值