2016年1月6日 星期三

Criteria2 (Hibernate3.x 三十五)

之前的CriteriaCriteria (Hibernate3.x 七),沒有加一對多,這裡將依官方的文件,做個整理
準備工作和三十四篇一樣
三十三篇有工具可以使用Criteria,看第一張圖就可以了,使用方法我試了好久,如下:


※一定要在ⓒ或ⓒ的子項按右鍵-->Hibernate Criteria Editor,然後畫面的右邊才會自動出現一些相關的語法,但語法不一定可以Run,像我的是修改後的結果

※我寫
java.util.List l = session.createCriteria(vo.Emp.class).list();
l.size();
也是可以,但如果跑迴圈就掛了,研究中…知道的回應一下吧!這個官網也寫的不是很清楚,網路上也很少人在討論這個

這裡還有jboss的教學影片,第二個「Edit and run HQL/JPA-QL queries」和第三個「Criteria Editor in Action」有介紹



Session s = HibernateUtil2.getSession();
Transaction tx = s.beginTransaction();
try {
    Criteria criteria = s.createCriteria(Emp.class);
    // ProjectionList plist = Projections.projectionList();
    // plist.add(Projections.rowCount());
    // plist.add(Projections.avg("sal"));
    // plist.add(Projections.groupProperty("dept"));
    // criteria.setProjection(plist);
    
    criteria.setProjection(
        Projections.projectionList()
        .add(Projections.rowCount())
        .add(Projections.avg("sal"))
        .add(Projections.groupProperty("dept"))
    );
    
    @SuppressWarnings("unchecked")
    List<Object[]> list = criteria.list();
    for (Object[] oA : list) {
        for (Object o : oA) {
            if(o instanceof Dept){
                Dept d = (Dept)o;
                System.out.println(d.getDname());
            } else {
                System.out.println(o);
            }
        }
    }
} catch (Exception e) {
    tx.rollback();
    System.err.println("例外錯誤!");
    e.printStackTrace();
} finally {
    if (s.isOpen()) {
        s.close();
    }
}

Criteria (Hibernate3.x 七)的最後一個匯總函數,這時因為是一對多,所以Emp.java沒有deptno關聯字段,這時只要指定集合就會幫我們關聯了

※註解的部分是較慢速的寫法




※sqlRestriction

Criteria cri = s.createCriteria(Emp.class);
cri.add(Restrictions.sqlRestriction(
    "{alias}.sal between ? and ?",
    new Object[] { 1500d, 3000d }, 
    new Type[] { StandardBasicTypes.DOUBLE, StandardBasicTypes.DOUBLE }));
// Hibernate.STRING;
    
@SuppressWarnings("unchecked")
List<Emp> list = cri.list();
System.out.println(list.size());
    
for (Emp e : list) {
    System.out.println(e.getEname());
}

※這是個overloading,共有三種,看API即可知道

※註解的Hibernate.STRING已經過時了,要用StandardBasicTypes

※?的個數、順序,對應第二個參數,第三個參數的型態對應第二個參數

※加上{alias},控制台會有from後面有「this_」,不加就沒有,可是不知道加這個有什麼用,我不加還是很正常的執行



※Property.forName

Criteria cri = s.createCriteria(Emp.class);
cri.add(Property.forName("sal").between(1500d, 3000d));

※結果和上面一樣




※createAlias

Criteria cri = s.createCriteria(Emp.class);
cri.createAlias("dept", "d");
cri.add(Restrictions.eq("d.deptno", 20));
// eqProperty

※dept是Emp的一方,如果有多個一方,可以用xxProperty




※Criteria.ALIAS_TO_ENTITY_MAP

Criteria cri = s.createCriteria(Emp.class);
cri.createAlias("dept", "d");
cri.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
    
@SuppressWarnings("unchecked")
List<Map<String, Object>> list = cri.list();
for (Map<String, Object> m : list) {
    Emp e = (Emp) m.get(Criteria.ROOT_ALIAS);
    System.out.println(e.getSal());
    System.out.println(e.getDept().getDname());
    
    Dept d = (Dept) m.get("d");
    System.out.println(d.getDeptno() + "\n");
}

※配合Criteria.ROOT_ALIAS可以關聯createAlias的別名




※FetchMode

Criteria cri = s.createCriteria(Emp.class);
cri.setFetchMode("dept", FetchMode.JOIN);
// FetchMode.EAGER 已廢棄
    
@SuppressWarnings("unchecked")
List<Emp> list = cri.list();
System.out.println(list.size());
    
for (Emp e : list) {
    System.out.println(e.getEname());
}

※FetchMode的EAGER和LAZY已廢棄,要用JOIN和SELECT,這個功能可以忽略設定檔的fetch設定





※Example

※範例一

Emp emp = new Emp();
emp.setJob("clerk");
    
Criteria cri = s.createCriteria(Emp.class);
cri.add(Example.create(emp).ignoreCase());
    
@SuppressWarnings("unchecked")
List<Emp> list = cri.list();
System.out.println(list.size());
    
for (Emp e : list) {
    System.out.println(e.getEname());
}

※使用Example.create(),然後裝進Criteria

※範例二


Emp emp = new Emp();
emp.setJob("s");
    
Example example = Example.create(emp);
example.excludeProperty("comm");
example.ignoreCase();
example.enableLike(MatchMode.START);
    
Criteria cri = s.createCriteria(Emp.class);
cri.add(example);
    
@SuppressWarnings("unchecked")
List<Emp> list = cri.list();
System.out.println(list.size());
    
for (Emp e : list) {
    System.out.println(e.getEname());
}

※MatchMode有四種
xxx就是上面的s
.EXACT:xxx,也就是沒有like,enableLike()裡面不放參數也是EXACT,繼然都不用了,所以enableLike都不打也是一樣

.START:xxx%
.END:%xxx
.ANYWHERE:%xxx%

※Example還有excludeNone()、excludeZeroes(),就是where條件必需是0、null的




※DetachedCriteria

離線查詢可以在session外面創建一個查詢,然後使用隨面一個session來執行


DetachedCriteria dcri = DetachedCriteria.forClass(Emp.class);
dcri.add(Property.forName("sal").ne(3000d));
    
Criteria cri = dcri.getExecutableCriteria(s).setMaxResults(5);
    
@SuppressWarnings("unchecked")
List<Emp> list = cri.list();
System.out.println(list.size());
    
for (Emp e : list) {
    System.out.println(e.getEname());
}

※控制台訊息:
select
    *
from
    ( select
          欄位
      from
          schema.Emp this_
      where
          this_.SAL<>?
    )
where
    rownum <= ?



※子查詢

DetachedCriteria avgSal = DetachedCriteria.forClass(Emp.class);
avgSal.setProjection(Property.forName("sal").avg());
    
Criteria cri = s.createCriteria(Emp.class)
.add(Property.forName("sal").gt(avgSal));
//.add(Subqueries.geAll(2500d, avgSal));
//.add(Subqueries.exists(avgSal.setProjection(Projections.property("sal"))));

※控制台訊息:
select
    欄位
from
    schema.Emp this_
where
    this_.SAL > (
        select
            avg(this_.SAL) as y0_
        from
            C##SCOTT.Emp this_
    )

※另外兩個註解的訊息是
...
where
    ? >= all (
        ...
    )


...
where
    exists (
        ...
    )




※自然identifier查詢

官方的意思是說,使用快取時常失效且效能太低,它說使用這種方式查詢會比較快
首先使用<natural-id>將想查詢的屬性包起來,這裡是將ename和job包起來
<id>
    ...
</id>
    
<natural-id>
    <property name="ename" type="java.lang.String" length="4">
        <column name="ENAME" length="4" />
    </property>
    
    <property name="job" type="java.lang.String">
        <column name="JOB" />
    </property>
</natural-id>
    
<property>
    ...
</property>


然後用Restrictions.naturalId()並開啟二級快取
Criteria cri = s.createCriteria(Emp.class);
NaturalIdentifier ni = Restrictions.naturalId();
ni.set("ename", "SMITH");
ni.set("job", "CLERK");
cri.add(ni).setCacheable(true);
    
@SuppressWarnings("unchecked")
List<Emp> list = cri.list();
System.out.println(list.size());
    
for (Emp e : list) {
    System.out.println(e.getSal());
}

※開啟二級快取可看第九篇

※我試的結果,不管有沒有開啟二級快取或者用<natural-id>都查的到,至於有沒有比較快,我是沒什麼感覺啦!應該是資料太少了吧!


沒有留言:

張貼留言