2HQL及自增主键

1HQL
Hibernate Query Language是一种面向对象的查询语言,HQL的操作对象时类,实例,属性;与EJB3 QL很接近。
HQL的功能非常丰富,where子句后支持的运算符异常丰富,不仅包括SQL的运算符,还包括EJB-QL的运算符等。
除了Java类与属性的名称外,查询语句对大小些并不敏感。


HQL 不支持union联合查询。




select子句
select子句用于确定选择出的属性,当然select选择的属性必须是from后持久化类包含的属性。例如:
select p.name from Person as p
这个select子句与EJB3 QL一样。


from子句
Hibernate中最简单的查询语句的形式如下:
from Cat
大多数情况下, 你需要指定一个别名, 原因是你可能需要 在查询语句的其它部分引用到Cat:from Cat as cat


where子句
where子句中允许使用大部分SQL支持的表达式:
   数学运算符+、–、*、/?等。


   比较运算符=、>、>=、<、<=、<>、!=、like等。


   逻辑运算符and、or、not等。


   in、not in、between、is null、is not null、is empty、is not empty、member of和not member of等。


   简单的case、case ... when ... then ... else ... end和case、case when ... then ... else ...       end等。


   字符串连接符value1 || value2或使用字符串连接函数concat(value1 , value2)。


   时间操作函数current_date()、current_time()、current_timestamp()、second()、minute()、hour()、day()、month()、year()等。


   HQL还支持EJB-QL 3.0所支持的函数或操作substring()、trim()、lower()、upper()、length()、locate()、abs()、sqrt()、bit_length()、coalesce()和nullif()等。


   还支持数据库的类型转换函数,如cast(... as ...),第二个参数是Hibernate的类型名,或者extract(... from ...),前提是底层数据库支持ANSI cast()?和extract()。
例如:
cast(arg1 as arg2);arg1是要转换的数据,arg2是目标类型(不是数据库类型名,是hibernate类型名:比如目标类型是varchar,必须写string)
SELECT CAST( ’2012-12-24′ AS DATE ) 把字符串转换成date类型
SELECT CAST( 2012 AS string ) 把数字转化成字符串
SELECT CAST( ‘baiduzhidao’ AS char(3) ) 取指定长度的字符


在HQL中子查询一般出现在where子句中,不能像sql语句那样在from后嵌套子查询,通过子查询来查询某个字段等。如:
List list=session.createQuery(“from Customer c where 1>(select count(o) from c.orders o)”).list();


下面这种子查询是正确的:
Query query=em.createQuery("select g.ginID as ginID,(select x.name from Gstorage x where x.gstorageID=g.glocationID) as gstorageN from Gin g ");


下面这种子查询是错误的:
Query query=em.createQuery("select o.ginID as ginID from ( select g.ginID as ginID from Gin g ) o");






   如果底层数据库支持如下单行函数sign()、trunc()、rtrim()、sin()。则HQL语句也完全可以支持。


   HQL语句支持使用?作为参数占位符,这与JDBC的参数占位符一致,也可使用命名参数占位符号,方法是在参数名前加冒号:,例如 :start_date和:x1等。


   当然,也可在where子句中使用SQL常量,例如'foo'、69、'1970-01-01 10:00:01.0'等。


   还可以在HQL语句中使用Java public static final 类型的常量,例如eg.Color.TABBY。


除此之外,where子句还支持如下的特殊关键字用法。


   in与between...and可按如下方法使用:
from DomesticCat cat where cat.name between 'A' and 'B'
from DomesticCat cat where cat.name in ( 'Foo','Bar','Baz')


   当然,也支持not in和not between...and的使用,例如:
from DomesticCat cat where cat.name not between 'A' and 'B'
from DomesticCat cat where cat.name not in ( 'Foo','Bar','Baz' )


   子句is null与is not null可以被用来测试空值,例如:
from DomesticCat cat where cat.name is null;
from Person as p where p.address is not null;


   size关键字用于返回一个集合的大小,例如:
from Cat cat where cat.kittens.size > 0
from Cat cat where size(cat.kittens) > 0


对于有序集合,还可使用minindex与maxindex函数代表最小与最大的索引序数。同理,可以使用minelement与maxelement函数代表集合中最小与最大的元素。例如:
from Calendar cal where maxelement(cal.holidays) > current date
from Order order where maxindex(order.items) > 100
from Order order where minelement(order.items) > 10000


where子句中,有序集合的元素(arrays, lists, maps)可以通过[ ]运算符访问。例如:
//items是有序集合属性,items[0]代表第一个元素
from Order order where order.items[0].id = 1234


//holidays是map集合属性,holidays[national day]代表其中一个元素
select person from Person person, Calendar calendar
where calendar.holidays['national day'] = person.birthDay
and person.nationality.calendar = calendar


//下面同时使用list 集合和map集合属性
select item from Item item, Order order
where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11
select item from Item item, Order order
where order.items[ maxindex(order.items) ] = item and order.id = 11


在[]中的表达式甚至可以是一个算术表达式,例如:
select item from Item item, Order order
where order.items[ size(order.items) - 1 ] = item






连接查询
迫切左外连接
   from User u left join fetch u.student s where u.name like '%java%'


左外连接
左连接就是要把左边这个表里面的所有的数据显示出来。
   from User u left join u.student s where u.name like '%java%'


迫切内连接
   from User u inner join fetch u.student where u.name like '%java%'


内连接
内连接是把所有的相等的,完全符合条件的列出来。
内连(join).可以将inner 关键字省略,默认就是内连接。
   from User u inner join u.student where u.name like '%java%'


右外连接
   from User u right join u.student where u.name like '%java%' 


HQL中的条件用with即:left join ... with...


SQL中的条件用on即:left join ... on...




Fetch:
在我们查询User对象的时候,默认只有User的内容,并不包含student的信息,如果在User.hbm.xml里设置lazy="true"的话同时又想取出关联的所有student内容,那么可以使用fetch。


order by子句
排序order by
HQL和SQL的使用方法很类似,"ASC"和"DESC"分别为升序和降序,如果不显式注明,HQL中默认为asc升序。
//先按照年龄降序排序,然后再按出生日期升序排序
Query query = sessionFactory.getCurrentSession().createQuery("select p from Person p order by p.age desc, p.birthday asc");


group by子句
分组查询,大部分标准的SQL聚集函数都可以在HQL语句中使用,比如:
count(),sum(),max(),min(),avg()等。
select cat.color, sum(cat.weight), count(cat) from Cat cat group by cat.color
Query query=sessionFactory.getCurrentSession().createQuery("select p.sex,count(*) from Person p group by p.sex");




HQL和可以使用和SQL那样的grouping,group by rollup(...)
如:
select g.belongOrganID,g.customerN,g.vtype,(case when grouping(g.belongOrganID)=0 then 1 when grouping(g.belongOrganID)=1 then 0 end )+(case when grouping(g.customerN)=0 then 1 when grouping(g.customerN)=1 then 0 end )+(case when grouping(g.vtype)=0 then 1 when grouping(g.vtype)=1 then 0 end ),uuid() as ID,count(*) as count, sum(g.totoalPrice) as totoalPrice from Gin o where 1=1  group by rollup(g.belongOrganID,g.customerN,g.vtype) 








聚合查询
HQL也支持查询中的聚合函数,目前HQL支持的聚合函数包括:
avg(),count(),max(),min(),sum() 


distinct
有时查询结果集中有相同的数据,关键词distinct用于返回唯一不同的数据。
select [distinct] object(variable) from abstractschemaname [as] variable [where value comparison value]




子查询
如果底层数据库支持子查询,则可以在HQL语句中使用子查询。与SQL中子查询相似的是,HQL中的子查询也需要使用()括起来。如:
from Cat as fatcat
where fatcat.weight > ( select avg(cat.weight) from DomesticCat cat )


如果select中包含多个属性,则应该使用元组构造符:
from Cat as cat
where not ( cat.name, cat.color ) in (
    select cat.name, cat.color from DomesticCat cat
)


命名查询
命名查询也和EJB3 QL一样使用@NamedQuery注解。
@NamedQuery
我们可以使用@NamedQuery注释来定义命名查询,这个注释可以放在任何实体Bean的上方,但为了便于管理,最好放在相关的实体Bean上方。
@NamedQuery(name="MyQuery",query="select p from PersonFlight p where name like ?1")


@NamedQueries( {  
        @NamedQuery(name = "person.query", query = "from Person p  where p.id=? "),  
        @NamedQuery(name = "person.query1", query = "from Person p  where p.id=? ") })  
也可以在hbm.xml文件中配置命名查询:
<query name="findGroupsByUser">  
    <![CDATA[ 
    select distinct g 
    from org.jbpm.pvm.internal.identity.impl.MembershipImpl m 
      join m.user u 
      join m.group g 
    where u.id = :userId 
    ]]>  
  </query> 
Query query = session.getNamedQuery("findGroupsByUser");  
query.setInteger("userId", 25);  
List result= query.list();  






Hibernate org.hibernate.Query类
setParameter()方法:
在Hibernate的HQL查询中可以通过setParameter()方法邦定任意类型的参数,如下代码:
 String hql="from User user where user.name=:customername";//注意=:后不要有空格
 Query query=session.createQuery(hql);
 query.setParameter("customername",name,Hibernate.STRING);
如上面代码所示,setParameter()方法包含三个参数,分别是命名参数名称,命名参数实际值,以及命名参数映射类型。对于某些参数类型 setParameter()方法可
以更具参数值的Java类型,猜测出对应的映射类型,因此这时不需要显示写出映射类型,像上面的例子,可以直接这样写:
query.setParameter("customername",name); 但是对于一些类型就必须写明映射类型,比如java.util.Date类型,因为它会对应Hibernate的多种映射类型,比如
Hibernate.DATA或者Hibernate.TIMESTAMP。




setProperties()方法:
在Hibernate中可以使用setProperties()方法,将命名参数与一个对象的属性值绑定在一起,如下程序代码:
Customer customer=new Customer();
customer.setName("pansl");
customer.setAge(80);
Query query=session.createQuery("from Customer c where c.name=:name and c.age=:age");
query.setProperties(customer);
setProperties()方法会自动将customer对象实例的属性值匹配到命名参数上,但是要求命名参数名称必须要与实体对象相应的属性同名。






查询单个字段
         String hql = " select name from Users";      
         Query query = session.createQuery(hql);      
              
         List<String> list = query.list();      
        for(String str : list){      
             System.out.println(str);      
         }      
输出结果为:      
name1      
name2      
name3    




查询其中几个字段 
         String hql = " select name,passwd from Users";      
         Query query = session.createQuery(hql);      
        //默认查询出来的list里存放的是一个Object数组      
         List<Object[]> list = query.list();      
        for(Object[] object : list){      
             String name = (String)object[0];      
             String passwd = (String)object[1];      
                  
             System.out.println(name + " : " + passwd);      
         }      
输出结果为:      
name1 : password1      
name2 : password2      
name3 : password3    




修改默认查询结果(query.list())不以Object[]数组形式返回,以List形式返回
添加new list(),注意list里的l是小写的。也不需要导入包,这样通过query.list()出来的list里存放的不再是默认的Object数组了,而是List集合了  
        String hql = " select new list(name,passwd) from Users";  
        Query query = session.createQuery(hql);  
        //默认查询出来的list里存放的是一个Object数组,但是在这里list里存放的不再是默认的Object数组了,而是List集合了  
        List<List> list = query.list();  
        for(List user : list){  
            String name = (String)user.get(0);  
            String passwd = (String)user.get(1);  
              
            System.out.println(name + " : " + passwd);  
        }  
        /**
        输出结果为:
         name1 : password1
        name2 : password2
        name3 : password3
         */


修改默认查询结果(query.list())不以Object[]数组形式返回,以Map形式返回
添加new map(),注意map里的m是小写的。也不需要导入包,这样通过query.list()出来的list里存放的不再是默认的Object数组了,而是 map集合了      
         String hql = " select new map(name,passwd) from Users";      
         Query query = session.createQuery(hql);      
        //默认查询出来的list里存放的是一个Object数组,但是在这里list里存放的不再是默认的Object数组了,而是Map集合了      
         List<Map> list = query.list();      
        for(Map user : list){      
            //一条记录里所有的字段值都是map里的一个元素,key是字符串0,1,2,3....,value是字段值      
            //如果将hql改为:String hql = " select new map(name as username,passwd as password) from Users";,那么key将不是字符串0,1,2...了,而是"username","password"了      
             String name = (String)user.get("0");//get("0");是get(key),注意:0,1,2...是字符串,而不是整形      
             String passwd = (String)user.get("1");      
                  
             System.out.println(name + " : " + passwd);      
         }      
        /**  
         输出结果为:  
          name1 : password1  
         name2 : password2  
         name3 : password3  
          */  


修改默认查询结果(query.list())不以Object[]数组形式返回,以自定义类型形式返回
public class MyUser {      
     
    private String username;      
    private String password;      
//因为:String hql = " select new  com.domain.MyUser(name,passwd) from Users";所以必须要有接受2个参数的构造函数      
    public MyUser(String username,String password){      
        this.username = username;      
        this.password = password;      
    }      
          
    public String getUsername() {      
        return username;      
    }      
    public void setUsername(String username) {      
        this.username = username;      
    }      
    public String getPassword() {      
        return password;      
    }      
    public void setPassword(String password) {      
        this.password = password;      
    }      
          
          
}    


2使用HibernateCallBack
HibernateTemplate还提供了一种更加灵活的方式来操作数据库,通过这种方式可以完全使用Hibernate的操作方式。HibernateTemplate的灵活访问方式可通过如下两个方法完成
Object execute(HibernateCallback action)
List executeFind(HibernateCallback action)
这两个方法都需要一个HibernateCallback的实例,HibernateCallback实例可在任何有效的Hibernate数据访问中使用。程序开发者通过HibernateCallback,可以完全使用Hibernate灵活的方式来访问数据库,解决Spring封装 Hibernate后灵活性不足的缺陷。


HibernateCallback 是一个接口,该接口包含一个方法doInHibernate(org.hibernate. Session session),该方法只有一个参数Session。在开发中提供HibernateCallback实现类时,必须实现接口里包含的 doInHibernate方法,在该方法体内即可获得Hibernate Session的引用,一旦获得了Hibernate Session的引用,就可以完全以Hibernate的方式进行数据库访问。
注意:doInHibernate方法内可以访问Session,该Session对象是绑定在该线程的Session实例。该方法内的持久层操作,与不使用Spring时的持久层操作完全相同。这保证了对于复杂的持久层访问,依然可以使用Hibernate的访问方式。


下面的代码对HibernateDaoSupport类进行扩展(虽然Spring 2.0的HibernateTemplate提供了一个分页方法setMaxResults,但仅此一个方法依然不能实现分页查询),这种扩展主要是为该类增加了3个分页查询的方法,分页查询时必须直接调用Hibernate的Session完成,因此,必须借助于HibernateCallBack的帮助。
public class YeekuHibernateDaoSupport extends HibernateDaoSupport
{
    /**
     * 使用hql 语句进行分页查询操作
     * @param hql 需要查询的hql语句
     * @param offset 第一条记录索引
     * @param pageSize 每页需要显示的记录数
     * @return 当前页的所有记录
     */
    public List findByPage(final String hql,
         final int offset, final int pageSize)
    {
        //HibernateDaoSupport已经包含了getHibernateTemplate()方法
        List list = getHibernateTemplate().executeFind(new
        HibernateCallback()
            {
                public Object doInHibernate(Session session)
                    throws HibernateException, SQLException
                //该方法体内以Hibernate方法进行持久层访问
                {
//注意setFirstResult是从0开始的,0就是第一页的数据
                    List result = session.createQuery(hql)
                                         .setFirstResult(offset)
                                         .setMaxResults(pageSize)
                                         .list();
                    return result;
                }
            });
        return list;
    }
    /**
     * 使用hql 语句进行分页查询操作
     * @param hql 需要查询的hql语句
     * @param value 如果hql有一个参数需要传入,value就是传入的参数
     * @param offset 第一条记录索引
     * @param pageSize 每页需要显示的记录数
     * @return 当前页的所有记录
     */
    public List findByPage(final String hql , final Object value ,
         final int offset, final int pageSize)
    {
        List list = getHibernateTemplate().executeFind(new
        HibernateCallback()
            {
                public Object doInHibernate(Session session)
                    throws HibernateException, SQLException
                {
                    //下面查询的是最简单的Hiberante HQL查询
                    List result = session.createQuery(hql)
                                         .setParameter(0, value)
                                         .setFirstResult(offset)
                                         .setMaxResults(pageSize)
                                         .list();
                    return result;
                }
            });
        return list;
    }
    /**
     * 使用hql 语句进行分页查询操作
     * @param hql 需要查询的hql语句
     * @param values 如果hql有多个参数需要传入,values就是传入的参数数组
     * @param offset 第一条记录索引
     * @param pageSize 每页需要显示的记录数
     * @return 当前页的所有记录
     */
    public List findByPage(final String hql, final Object[] values,
         final int offset, final int pageSize)
    {
        List list = getHibernateTemplate().executeFind(new
        HibernateCallback()
            {
                public Object doInHibernate(Session session)
                    throws HibernateException, SQLException
                {
                    Query query = session.createQuery(hql);
                    for (int i = 0 ; i < values.length ; i++)
                    {
                        query.setParameter( i, values[i]);
                    }
                    List result = query.setFirstResult(offset)
                                       .setMaxResults(pageSize)
                                       .list();
                    return result;
                }
            });
        return list;
    }
}
在上面的代码实现中,直接使用了getHibernateTemplate()方法,这个方法由Hibernate- DaoSupport提供。而YeekuHibernateDaoSupport是HibernateDaoSupport的子类,因此,可以直接使用该方法。
当实现doInHibernate(Session session)方法时,完全以Hibernate的方式进行数据库访问,这样保证了Hibernate进行数据库访问的灵活性。
注意:Spring提供的XxxTemplate和XxxCallBack互为补充,二者体现了Spring框架设计的用心良苦:XxxTemplate对通用操作进行封装,而XxxCallBack解决了封装后灵活性不足的缺陷。




3Hibernate产生的自增主键
使用@GeneratedValue和@GenericGenerator
针对不同的数据库可以同时使用
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)


针对mysql
 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)


针对oracle
       @Id
       @GeneratedValue(strategy = GenerationType.SEQUENCE,generator="s_gen")
       @SequenceGenerator(name="s_gen",sequenceName="s_seq")
说明:@GeneratedValue()的strategy属性支持5中id生成器:除上面3中外还有GenerationType.TABLE。




@GeneratedValue:主键的产生策略,通过strategy属性指定。
主键产生策略通过GenerationType来指定。GenerationType是一个枚举,它定义了主键产生策略的类型。
  AUTO 自动选择一个最适合底层数据库的主键生成策略。如MySQL会自动对应auto increment。这个是默认选项,即如果只写@GeneratedValue,等价于@GeneratedValue(strategy=GenerationType.AUTO)。
  IDENTITY 表自增长字段,Oracle不支持这种方式。
  SEQUENCE 通过序列产生主键,MySQL不支持这种方式。
  TABLE 通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。
不同的JPA实现商生成的表名是不同的,如 OpenJPA生成openjpa_sequence_table表,Hibernate生成一个hibernate_sequences表,而TopLink则生成sequence表。这些表都具有一个序列名和对应值两个字段,如SEQ_NAME和SEQ_COUNT。
在我们的应用中,一般选用@GeneratedValue(strategy=GenerationType.AUTO)这种方式,自动选择主键生成策略,以适应不同的数据库移植。




@GenericGenerator
自定义主键生成策略,由@GenericGenerator实现。
hibernate在JPA的基础上进行了扩展,可以用一下方式引入hibernate独有的主键生成策略,就是通过@GenericGenerator加入的。例如:
        @Id
@Column(name="id",length=32)
@GeneratedValue(generator = "paymentableGenerator")
@GenericGenerator(name = "paymentableGenerator", strategy = "uuid")   
private String roleID;



name属性指定生成器名称。
strategy属性指定具体生成器的类名。
parameters得到strategy指定的具体生成器所用到的参数。


对于这些hibernate主键生成策略和各自的具体生成器之间的关系,在org.hibernate.id.IdentifierGeneratorFactory中指定了
static {   
   GENERATORS.put("uuid", UUIDHexGenerator.class);   
   GENERATORS.put("hilo", TableHiLoGenerator.class);   
   GENERATORS.put("assigned", Assigned.class);   
   GENERATORS.put("identity", IdentityGenerator.class);   
   GENERATORS.put("select", SelectGenerator.class);   
   GENERATORS.put("sequence", SequenceGenerator.class);   
   GENERATORS.put("seqhilo", SequenceHiLoGenerator.class);   
   GENERATORS.put("increment", IncrementGenerator.class);   
   GENERATORS.put("foreign", ForeignGenerator.class);   
   GENERATORS.put("guid", GUIDGenerator.class);   
   GENERATORS.put("uuid.hex", UUIDHexGenerator.class); //uuid.hex is deprecated   
   GENERATORS.put("sequence-identity", SequenceIdentityGenerator.class);   
}


native
根据地层数据库的能力选择identity,sequence或hilo中的一个。
@GeneratedValue(generator = "paymentableGenerator") 
@GenericGenerator(name = "paymentableGenerator", strategy = "native")


uuid
用一个128-bit的UUID算法生成字符串类型的标识符,这在一个网络中是唯一的。UUID被编码为一个32为16进制数字的字符串。
@GeneratedValue(generator = "paymentableGenerator")
@GenericGenerator(name = "paymentableGenerator", strategy = "uuid")


hilo
使用一个高/低位算法高效的生成long,short或int类型的标识符。给定一个表和字段(默认分别是hibernate_unique_key和next_hi)作为高位值的来源。高/低位算法生成的标识符只在一个特定的数据库中是唯一的。
@GeneratedValue(generator = "paymentableGenerator")
@GenericGenerator(name = "paymentableGenerator", strategy = "hilo")


assigned
让应用升序在save()之前为对象分配一个标识符。这是<gengerator>元素没有指定时的默认生成策略。
@GeneratedValue(generator = "paymentableGenerator")
@GenericGenerator(name = "paymentableGenerator", strategy = "assigned")


identity
对于DB2,MySQL,MS SQL Server,Sybase和HypersonicSQL的内置标识字段提供支持,返回的标示符是long,short或int类型的。整数递增。
@GeneratedValue(generator = "paymentableGenerator")
@GenericGenerator(name = "paymentableGenerator", strategy = "identity")


select
通过数据库触发器选择一些唯一主键的行返回主键值分配一个主键。
@GeneratedValue(generator = "paymentableGenerator"
@GenericGenerator(name="select", strategy="select", parameters = { @Parameter(name = "key", value = "idstoerung") })


sequence
在DB2,PostgreSQL,Oracle,SAP DB,McKoi中使用序列(sequence),而在Interbase中使用生成器(generator)。返回的标示符是long,short或int类型的。
@GeneratedValue(generator = "paymentableGenerator")
@GenericGenerator(name = "paymentableGenerator", strategy = "sequence", parameters = { @Parameter(name = "sequence", value = "seq_payablemoney") })


seqhilo
使用一个高/低位算法高效的生成long,short或int类型的标识符,给定一个数据库序列(sequence)的名字。
@GeneratedValue(generator = "paymentableGenerator")
@GenericGenerator(name = "paymentableGenerator", strategy = "seqhilo", parameters = { @Parameter(name = "max_lo", value = "5") })


increment
用于为long,short或int类型生成唯一标识,只有在没有其他进程往同一张表中插入数据时才能使用,在集群下不要使用。
@GeneratedValue(generator = "paymentableGenerator")
@GenericGenerator(name = "paymentableGenerator", strategy = "increment")


foreign
使用另一个相关联的对象的标识符。通常和<one-to-one>联合起来使用。
@GeneratedValue(generator = "idGenerator")
@GenericGenerator(name = "idGenerator", strategy = "foreign",
         parameters = { @Parameter(name = "property", value = "employee") }) 
例如:
@Entity  
public class Employee {   
  @Id   
  @GeneratedValue(generator = "idGenerator")   
  @GenericGenerator(name = "idGenerator", strategy = "foreign",   
          parameters = { @Parameter(name = "property", value = "info") })   
   Integer id;   
       
  @OneToOne  
   EmployeeInfo info;   
   ...   
}   




guid
在MS SQL Server和MySQL中使用数据库生成GUID字符串。
@GeneratedValue(generator = "paymentableGenerator")     
@GenericGenerator(name = "paymentableGenerator", strategy = "guid")    


uuid.hex
@GeneratedValue(generator = "paymentableGenerator")     
@GenericGenerator(name = "paymentableGenerator", strategy = "uuid.hex")    


sequence-identity
一种特别的序列生成策略,使用数据库序列来生成实际值,但将它和jdbc3的getGeneratedKeys结合在一起,使的在插入语句执行的时候就返回生成的值,目前只面向JDK1.4的oracle10g开放这一策略。
@GeneratedValue(generator = "paymentableGenerator")   
@GenericGenerator(name = "paymentableGenerator", strategy = "sequence-identity",   
          parameters = { @Parameter(name = "sequence", value = "seq_payablemoney") })   


在hbm.xml映射文件中,使用id生成策略
<id name="codeID" type="String">
 <column name="CODEID" length="32"/>
 <generator class="uuid.hex"/>
</id>


*******************
在hibernate的保存或更新完实体对象后,就可以通过实体对象得到其对应的id。


*********************
createSQLQuery(String str)
例如,Object obj=session.createSQLQuery("select o.name from organ o where o.id=1");
如果只查询一列并只有一个结果则返回Object,如果有多个结果则返回List<Object>。如果查询多列且有多个结果则返回List<Object[]>。
List<Object[]> listobj=session.createSQLQuery("select o.name,o.id from organ o");






******************
hql中+号的另一中作用:
createQuery("select new Vcolor(c.vcolorID,c.name) from Vconfig o,Vcolor c where o.vconfigID=:vconfigId and o.outterColor like '%'+c.vcolorID+'%' ");
表示从Vcolor中找出VcolorID在指定的Vconfig对象的outterColor属性中的vcolor对象。不能写成
like '%c.vcolorID%' 。这种写法其实和sql写法一样。


http://www.redsaga.com/hibernate-ref/3.x/zh-cn/html/queryhql.html




****************
case when:
1. select   sum(case when  otype='A' then price  when otype='B' then -price  end )  from  Entity  (sql中支持,但hql查询时,控制台查询语句缺少 ‘when otype='B' then -price ’,也就是只有otype='A' 的情况)
2.select sum(case when otype='A'  then  price  else -price end ) from Entity  (支持)
3. select sum(case when otype='A'  then  price  else  case when otype='B' then -price end end ) from Entity (支持)




*********************
inner join(内连接) 
left outer join(左外连接) 
right outer join(右外连接) 
full join (全连接,并不常用) 
 
HQL中的条件用with即:left join ... with...
SQL中的条件用on即:left join ... on...
语句inner join, left outer join 以及 right outer join 可以简写。 
from Cat as cat     join cat.mate as mate    left join cat.kittens as kitten 
 
通过HQL的with关键字,你可以提供额外的join条件。 
from Cat as cat     left join cat.kittens as kitten         with kitten.bodyWeight > 10.0
  
还有,一个"fetch"连接允许仅仅使用一个选择语句就将相关联的对象或一组值的集合随着他们的父对象的初始化而被初始化,这种方法在使用到集合的情况下尤其有用,对于关联和集合来说,它有效的代替了映射文件中的外联接 与延迟声明(lazy declarations).
 from Cat as cat     inner join fetch cat.mate    left join fetch cat.kittens 
 
一个fetch连接通常不需要被指定别名, 因为相关联的对象不应当被用在 where 子句 (或其它任何子句)中。同时,相关联的对象 并不在查询的结果中直接返回,但可以通过他们的父对象来访问到他们。
 from Cat as cat     inner join fetch cat.mate    left join fetch cat.kittens child    left join fetch child.kittens
  
假若使用iterate()来调用查询,请注意fetch构造是不能使用的(scroll() 可以使用)。fetch也不应该与setMaxResults() 或setFirstResult()共用,这是因为这些操作是基于结果集的,而在预先抓取集合类时可能包含重复的数据,也就是说无法预先知道精确的行数。fetch还不能与独立的 with条件一起使用。通过在一次查询中fetch多个集合,可以制造出笛卡尔积,因此请多加注意。对bag映射来说,同时join fetch多个集合角色可能在某些情况下给出并非预期的结果,也请小心。最后注意,使用full join fetch 与 right join fetch是没有意义的。
  
如果你使用属性级别的延迟获取(lazy fetching)(这是通过重新编写字节码实现的),可以使用 fetch all properties 来强制Hibernate立即取得那些原本需要延迟加载的属性(在第一个查询中)。
from Document fetch all properties order by name 
from Document doc fetch all properties where lower(doc.name) like '%cats%'








************************
query.setResultTransformer方法


我们如果查询出实体类部分属性,hibernate会自动帮你封装成为object对象[].可是,我们想直接用对象怎么办?难道还要一个一个的setter循环赋值给VO。


例如:
public SureOrder getSureOrderVO(Integer productId) {
    String hql = "select pd.id as prodid,pd.cuxiaoPrice as cuxiaoPrice,pd.types as types,pd.price as price,pd.newprice as newprice,p.nodeId,p.imgurl as imgurl,p.types as types,p.factId as factId,p.qianYueId as qianyueId,p.guiGe as guiGe,p.name as name,p.pinPai as pinPai from Product pd,Prod p where p.id=pd.prodId and pd.id =?";
    Query query = productDao.getProductDetail(productId,hql);
    //主要起作用的就是下面的这个方法:SureOrder是我要封装的VO类.这样hibernate在执行hql查询的时候,会直接将结果封装为SureOrder对象.
    List list = query.setResultTransformer(Transformers.aliasToBean(SureOrder.class)).list();
    if(!list.isEmpty()){
      return (SureOrder) list.get(0);
    }
    return null;
  }




**************************


select中的new map前面也可以使用distinct :
select distinct new map(...)











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值