20120321hibernate
Hibernate
1,error:Path expected for join!
错误的写法:select lin from LoginInfo lin join person where lin.loginId =?
正确的写法: select lin from LoginInfo lin join lin.person where lin.loginId =?
注意:用这种方法进行关联查询的话,要确保对几个相关联实体的获取都要在session.getTransaction().commit();语句之前,即在session未关闭之前,
否则会报问题2一样的错误。
2,error:org.hibernate.LazyInitializationException: could not initialize proxy - no Session
设置lazy="false"或用1的办法。
总结:尽量不要设置lazy="false"来抓取关联的实体,这样不够灵活,而应该在需要时在查询语句中用join来抓取需要的实体。
3,The uniqueResult() method offers a shortcut if you know your query will only return a single object:
Cat mother = (Cat) session.createQuery(
"select cat.mother from Cat as cat where cat = ?")
.setEntity(0, izi)
.uniqueResult();
4,根据输入参数调整的查询语句
String searchStr = "";
if(searchType.equals("loginId")){
searchStr = "select lin from LoginInfo lin join lin.person where lin.loginId =?";
}else{
searchStr = "select lin from LoginInfo lin join lin.person where lin.person.mailAddr =?";
}
或者
searchStr = "select lin from LoginInfo lin join lin.person where lin."+searchType+"=?";
但要注意,jsp中searchType的值为loginId和person.mailAddr(而不是mailAddr),保证符合语境。
5,数据库语句的错误
<property
formula="(select trunc(li.toDate - li.fromDate,'hh24') from LEAVEINFO li where li.leaveId=leaveId)"
name="rangeDays"/>
其中,li.toDate和li.fromDate都是Date类型,两个Date相减结果为Number类型数据,因此不能用
trunc(li.toDate - li.fromDate,'hh24')。
此类错误可以先在sql developer等ide中先测试语句的正确与否,再代入程序中。
6,对象持久化(注意持久化对象的操作与hql查询操作之间的区别)
如果在映射文件中不设置LoginInfo类中Person属性的lazy为false的话,
loginInfo = (LoginInfo) session.get(LoginInfo.class, uId);//无论这里是用load还是get
person = loginInfo.getPerson();
这里取出来的person的属性都是空的,说明person没有随着loginInfo一起被取出来。
而通过在随后添加对person的操作之后,person的各属性值将可以从数据库中获取到。
loginInfo = (LoginInfo) session.load(LoginInfo.class, uId);
person = loginInfo.getPerson();
dayRecord = person.getDayRecord();
session.get(LoginInfo.class, uId);这种语句似乎不会受session.getTransaction().commit();的影响来完成所有对象的fetch。
7,当使用hql查询时,如果from语句中使用了join,那么返回的将是由join前后实体组成的集合,若只要返回一个实体对象,需添加select。
如
from LeaveInfo lei inner join lei.requestor req where req.personId=?
//将返回[LeaveInfo,Person]数组
select distinct lei from LeaveInfo lei inner join lei.requestor req where req.personId=?
//将返回list<LeaveInfo>
select distinct lei from LeaveInfo lei inner join fetch lei.requestor req where req.personId=?
//通过fetch同时获取requestor的Person类,从而可以使用leaveInfo.getRequestor().getFullName()。
8,设置cascade="all,delete-orphan" 或cascade="all-delete-orphan"的话就报错:
ERROR org.springframework.web.context.ContextLoader.initWebApplicationContext:308 - Context initialization failed。
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is org.hibernate.InvalidMappingException: Could not parse mapping document from input stream
??????????
9,单端关联(<one-to-one>、<many-to-one>)上的抓取策略
可以给单端关联的映射元素添加fetch属性。Fetch属性有两个可选值
a、 select:作为默认值,它的策略是当需要使用到关联对象的数据时,另外单独发送一条select语句抓取当前对象的关联对象的数据,即延迟加载;
b、 join:它的策略是在同一条SELECT语句使用内连接来获得对象的数据和它的关联对象的数据。此时关联对象的延迟加载失败;
但在实际测试中,即使用了fetch="join",还是没有使用内连接来同时获得关联对象:
select
logininfo0_.LOGINID as LOGINID2_0_,
logininfo0_.PASS as PASS2_0_,
logininfo0_.ROLE as ROLE2_0_
from
LOGININFO logininfo0_
where
logininfo0_.LOGINID=?
fetch参数指定了关联对象抓取的方式是select查询还是join查询,select方式时先查询返回要查询的主体对象(列表),再根据关联外键id,每一个对象发一个select查询,获取关联的对象,形成n+1次查询;
而join方式,主体对象和关联对象用一句外键关联的sql同时查询出来,不会形成多次查询。
fetch策略用于定义 get/load一个对象时,如何获取非lazy的对象/集合。如果你的关联对象是延迟加载的,它当然不会去查询关联对象。
10,hql查询语句中,字符和数字会自动进行隐式转换。
String hql = "select lei from LeaveInfo lei where lei.leaveStatus=? order by lei.raiseDate";
如果方法为getToApproveTable(String,String,int);
result = getToApproveTable(hql,"3",pageNow);
如果方法为getToApproveTable(String,int,int);
result = getToApproveTable(hql,3,pageNow);
两者查询返回结果相同。
11,hibernate 使用sql-type之后无法建表。
HHH000388: Unsuccessful: create table LOGININFO (LOGINID VARCHAR2 not null, PASS VARCHAR2, ROLE VARCHAR2, primary key (LOGINID))
ERROR org.hibernate.tool.hbm2ddl.SchemaUpdate.execute:236 - ORA-00906: missing left parenthesis
原因:创建varchar2类型的列时要有定义位数,如VARCHAR2(10)。
<column name="LEAVESTATUS" precision="2" />,可创建,但是NUMBER的precision设置无效。
<column name="LEAVESTATUS" sql-type="NUMBER"/>,也可创建;
<column name="LEAVESTATUS" precision="2" scale="0" sql-type="NUMBER"/>,也可创建,但是NUMBER的precision和scale设置无效,生成列类型为NUMBER,无大小范围。
<column length="15" name="LEAVETYPE"/>,可创建,且length设置有效。
<column length="15" name="LEAVETYPE" sql-type="VARCHAR2"/>,出错,原因在于生成的sql语句中,该varchar2类型的列(LEAVETYPE)没有定义位数,即
create table LEAVEINFO (LEAVEID number(10,0) not null, LEAVETYPE varchar2, LEAVEREASON varchar2(200 char),......
从而造成missing left parenthesis的错误。似乎length的设置无效。
<column name="LEAVETYPE" sql-type="varchar2(15)"/>,这样直接设置类型及其大小倒可以创建,其中15单位为byte。
<column name="FLOATINGDAYS" sql-type="NUMBER(3,0)"/>,这样也可以。
注意数据length的位置,在property里设置的length是程序中属性的,而数据库中对应列的length要写在column里。
<property generated="never" length="20" name="firstName" type="java.lang.String">
<column length="20" name="FIRSTNAME" />
</property>
12,对于多个不同类型参数用于hql查询,可以在制作参数列表时都转换成str,然后在查询语句中再转成原来的类型。
如,对于int类型的参数:
stringList.add(Integer.toString(searchCriLR.getLeaveStatus()));
而在hql语句中用:"...and lei.leaveStatus=to_number(?)"重新转成number类型。
对于Date,可以:
java.sql.Date fromD =new java.sql.Date(searchCriLR.getFromDate().getTime());
而在hql语句中:
"...lei.fromDate between to_date(?,'yyyy-mm-dd')... "
其中的format:'yyyy-mm-dd'不能省略,因省略的话会调用默认的格式,而oracle默认的格式是:DD-MON-YY。因而省略格式会造成literal does not match format string错误。
13,让条件不区分大小写
DetachedCriteria result = DetachedCriteria.forClass(LeaveInfo.class);
result.add(Restrictions.eq("req.firstName",searchCriLR.getFirstName()).ignoreCase());
14,
条件查询
http://www.redsaga.com/hibernate-ref/3.x/zh-cn/html/querycriteria.html
15,实例查询
Criteria criteria = this.sessionFactory.getCurrentSession()
.createCriteria(Person.class);
criteria.add(Example.create(person));
因为person取自页面中,即使不为其赋值,也会自动默认为""而非null值,而只有null值的属性才会被忽略而不进入搜索条件中,所以这些非null值的属性仍然进入搜索表达式(导致搜索结果为空):
select
*
from
...
where
(
this_.FIRSTNAME=?
and this_.LASTNAME=?
and this_.DEPARTMENT=?
and this_.LOCATION=?
and this_.MAILADDR=?
and (
select
p.firstName||','||p.lastName
from
PERSON p
where
p.personId=this_.personId
)=?
)
order by
this_.PERSONID asc )
where
rownum <= ?
添加了.excludeZeroes()之后还是没用,因为空字符串""是有值的。
回到Person的类文件中,在声明属性时不为其赋值。
即将private String personId="";
改为private String personId;
但是页面传值时自动为其赋值为""。
最后在Dao层函数里新建一个person,并只将有值的属性赋给它,才解决了问题。
新问题是:personId不为0时仍然没有纳入搜索条件。标识符会被忽略!(版本属性、标识符和关联被忽略)