2012年2月22日 星期三

Hibernate Criteria




分頁
@SuppressWarnings("unchecked")
public List listByUserIdAndState(int userId, int state, int first, int size) {

    Criteria criteria = ss.createCriteria(User.class);
    criteria.add(Restrictions.eq("userId", userId));
    criteria.add(Restrictions.eq("state", state));
    criteria.setFirstResult(first);
    criteria.setMaxResults(size);

    return criteria.list();
}

排序

@SuppressWarnings("unchecked")
public List listByUserIdAndState(int userId, int state, int first, int size) {

    Criteria criteria = ss.createCriteria(User.class);
    criteria.add(Restrictions.eq("userId", userId));
    criteria.add(Restrictions.eq("state", state));
    criteria.addOrder(Order.desc("updateTime"));
    criteria.setFirstResult(first);
    criteria.setMaxResults(size);

    return criteria.list();
}

使用add()方法加入條件時, 預設是使用and來組合條件, 若要用or

    Criteria criteria = ss.createCriteria(User.class);
    criteria.add(Restrictions.eq("userId", userId));
    criteria.add(Restrictions.or(
          Restrictions.eq("state",  new Integer(1) ),
          Restrictions.isNull("state")
    ));
    return criteria.list();

Like

    Criteria criteria = ss.createCriteria(User.class);
    criteria.add(Restrictions.eq("userId", userId));
    criteria.add(Restrictions.like("phone", "%" + phone + "%"));
    return criteria.list();

Restrictions 
Restrictions.eq
Restrictions.allEq (參數為map)
Restrictions.gt
Restrictions.ge
Restrictions.lt
Restrictions.le
Restrictions.between
Restrictions.like
Restrictions.in
Restrictions.and
Restrictions.or
Restrictions.isNull
Restrictions.isNotNull
Restrictions.sqlRestriction
Order.asc
Order.descMatchMode.EXACT  = "like 'value'"
MatchMode.ANYWHERE = "like '%value%'"
MatchMode.START = like 'value%'"
MatchMode.END = "like '%value'"


Disjunction 

      Criteria criteria = ss.createCriteria(User.class);
      criteria.add(Restrictions.eq("userId", userId));
      Criterion phoneCriterion = Restrictions.like("phone", phone, MatchMode.ANYWHERE);
      Criterion mobileCriterion = Restrictions.like("mobile", mobile, MatchMode.ANYWHERE);
      Disjunction disjunction = Restrictions.disjunction();
      disjunction.add(phoneCriterion);
      disjunction.add(mobileCriterion);
      criteria.add(disjunction);

      return criteria.list();



Count
public int countByUserIdAndState(int userId, int state) {

    Criteria criteria = ss.createCriteria(User.class);
    criteria.add(Restrictions.eq("userId", userId));
    criteria.add(Restrictions.eq("state", state));
    criteria.setProjection(Projections.rowCount());

    return (Integer) criteria.uniqueResult();
}

group by
    ProjectionList projectionList = Projections.projectionList();
    projectionList.add(Projections.groupProperty("area"), "area");
    projectionList.add(Projections.rowCount(), "userId");
   
    Criteria criteria = ss.createCriteria(User.class);
    criteria.add(Restrictions.eq("userId", userId));
    criteria.setProjection(projectionList);
   
    return criteria.list();

回傳結果
public List<HashMap<String, Integer>> listUser(int userId) {
      ProjectionList projectionList = Projections.projectionList();
      projectionList.add(Projections.groupProperty("area"), "area");
      projectionList.add(Projections.rowCount(), "userId");
      Criteria criteria = ss.createCriteria(User.class);
      criteria.add(Restrictions.eq("userId", userId));
      criteria.setProjection(projectionList);
      criteria.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
      return criteria.list();
}



Example 用目前的物件查詢


User user = new User(); 
user.setAge(new Integer(30)); 
Criteria criteria = session.createCriteria(User.class); 
criteria.add(Example.create(user)); 
List users = criteria.list();

Hibernate: select this_.id as id0_0_, this_.name as name0_0_, this_.age as age0_0_ from T_USER this_ where (this_.age=?)

sqlRestriction  - 直接下SQL

Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.sqlRestriction(
"{alias}.name LIKE (?)", "todd%", Hibernate.STRING));
List users = criteria.list();

HQL

String hql = "select * from user"; 
Query query = session.createQuery(hql); 
list = query.list();

2012年2月21日 星期二

一堆的 if 與 else 時怎麼處理

公司裡有一段 code 是這麼寫著


...
...
String 名稱1;
String 名稱2;
String 名稱3;
if (paramater.equals("actionA")) {
  名稱1 = ....;
  名稱2 = ....;
  名稱3 = ....;
} else if (paramater.equals("actionB")) {
  名稱1 = ....;
  名稱2 = ....;
  名稱3 = ....;
} else if (paramater.equals("actionC")) {
  名稱1 = ....;
  名稱2 = ....;
  名稱3 = ....;
} else if (paramater.equals("actionC")) {
  名稱1 = ....;
  名稱2 = ....;
  名稱3 = ....;
} else if ....
...
...
...


看到了很多的 if 與 else

這時會有一個問題,就是當我要寫增加或修改時,必須先找到合適的那一段後,再插入自己的程式碼,可能會有一些不方便的地方,如:
1. 程式太過攏長, 久了會不好維護.
2. 當有順序要對掉時, 顯得很麻煩.

於是再不動架構的情況下,找了些資訊看能不能改寫這段程式:
參考了良葛格的筆記(Design Patter). Chain of Responsibility

先看一下改過的程式長什麼樣子,再來討論這個 Design Patter 的用處。

首先程式碼將每一段if else 切成各個 Class 去實作, 而主程式只是將每個 Class 串接起來即可.

其每一個Class 的內容如下:

MailsMetaChain
public class MailsMetaChain extends MetaChain {

  public void handleRequest(HttpServletRequest request) {
    if (getPart(request).equals(PARAM_VALUE_MAILS)) {
      processMailsMetaInfo(request);
    } else if (next != null) {
      next.handleRequest(request);
    } else {
      defaultRequest(request);
    }
  }

  private void processMailsMetaInfo(HttpServletRequest request) {
    String title = new StringBuilder()
          .append(IhergoProperties.get("label.mail"))
          .append(" - ")
          .append(IhergoProperties.get("web.title")).toString();
    setMeta(request, title, "", "");
  }
}

其 extends 的 Class MetaChain
public abstract class MetaChain {

  private static final String PARAAM_KEY_PART = "part";
  private static final String PARAAM_KEY_VIEW = "view";
  private static final String PARAAM_KEY_TAB = "tab";

  ... 中間省略
  
  protected MetaChain next;

  public void setNextMetaChain(MetaChain next) {
    this.next = next;
  }

  /**
   * extends class 必須實做的功能
   * 
   * @param request
   */
  protected abstract void handleRequest(HttpServletRequest request);

  /**
   * 如果沒有 match 到時, 用 default 的
   * 
   * @param request
   */
  protected void defaultRequest(HttpServletRequest request) {
    StringBuilder title = new StringBuilder();
    title.append(IhergoProperties.get("web.title"));
    title.append(" - ");
    title.append(IhergoProperties.get("web.categorys"));
    
    String keyword = IhergoProperties.get("web.keywords");
    String desc = IhergoProperties.get("web.description");
    setMeta(request, title.toString(), keyword, desc);
  }

  /**
   * 抓取 part
   * 
   * @param request
   * @return
   */
  protected String getPart(HttpServletRequest request) {
    if (request != null) {
      return StringUtils.defaultIfEmpty(request.getParameter(PARAAM_KEY_PART),
          "");
    }
    return "";
  }

  /**
   * 抓取 view
   * 
   * @param request
   * @return
   */
  protected String getView(HttpServletRequest request) {
    if (request != null) {
      return StringUtils.defaultIfEmpty(request.getParameter(PARAAM_KEY_VIEW),
          "");
    }
    return "";
  }

  /**
   * 抓取 tab
   * 
   * @param request
   * @return
   */
  protected String getTab(HttpServletRequest request) {
    if (request != null) {
      return StringUtils.defaultIfEmpty(request.getParameter(PARAAM_KEY_TAB), "");
    }
    return "";
  }

  protected void setMeta(HttpServletRequest request, String title,
      String keyword, String desc) {
    
    if (StringUtils.isBlank(title)) {
      title = new StringBuilder()
               .append(IhergoProperties.get("web.title"))
               .append(" - ")
               .append(IhergoProperties.get("web.categorys")).toString();
    }
    
    if (StringUtils.isBlank(keyword)) {
      keyword = IhergoProperties.get("web.keywords");
    }
    
    if (StringUtils.isBlank(desc)) {
      desc = IhergoProperties.get("web.description");
    }
    
    request.setAttribute("titleStr", title);
    request.setAttribute("keywordsStr", keyword);
    request.setAttribute("descriptionStr", desc);
  }

  ...
  ...

}


這樣看起來就很清楚明了了唷!!
其好處,以後只需找到自己的 Class 去修改就可以囉。
來看看Gof寫的一段話:

在一個介面中希望使用者一定可以得到相關的說明主題,如果子元件有說明的話,就顯示相關說明,否則的話就轉發給包括它的容器元件或父元件,以保證使用者的輔助說明請求一定可以得到回應。

當然這不是一種好的解法,也可以再更精進一點,如把每一個實作的 Class 改成 Singleton 必免 new 出太多的 Class
而如果可以改變架構的話,其實可以在進入action時,去實作 setTitle 這個 method ,在 BaseAction 中 implements ISetTitle 即可。