S2Hibernateの機能を使用するにあたり、JavaBeans、Dao(.java)、diconファイルの作成が必要になります。
通常のJavaBeanを作成します。S2Hibernateを意識する必要はありませが、Hibernateで利用できるように記述してください。
例)Dao実装(EmployeeDaoImpl.java)
- S2SessionFactory型のフィールドを定義。
private S2SessionFactory sessionFactory_;
- コンストラクタあるいはプロパティ経由で実装クラス(S2SessionFactoryImpl)を受け取るように記述。
public EmployeeDaoImpl(S2SessionFactory sessionFactory) {
sessionFactory_ = sessionFactory;
}
- 各メソッドでS2SessionFactoryからS2Sessionを取得し、処理を記述する。
public Employee getEmployee(int empno) {
List result = sessionFactory_.getSession().find(
HQL, new Integer(empno), Hibernate.INTEGER);
if (result.size() > 0) {
return (Employee) result.get(0);
} else {
return null;
}
}
-
Sessionのオープン・クローズ、トランザクション制御は必要ありません。
- S2SessionFactory.getSession()が返すオブジェクトは、HibernateのSessionのラッパーであるS2Sessionです。
実行できるメソッドはHibernateのSessionと同じで、検査例外(HibernateException)を実行時例外(HibernateRuntimeException)に変換してくれます。
そのため、HibernateExceptionをcatchしたくないクラスは特に何もする必要はありません。
catchする必要がある場合は、HibernateRuntimeExceptionでcatchしてgetCause()でHibernateExceptionを取り出します。
作成したDaoクラスとorg.seasar.hibernate.impl.S2SessionFactoryImplを追加します。
例)Employee.dicon
S2hibernate.daoを使うと、Sessionを意識せずにDaoを記述することができます。
S2hibernate.daoでは定数アノテーションという技術を使い、ソースコードにメタデータを記述するだけで動作するようになります。
定数アノテーションとHQL文だけを書けば、動作するようになるので開発効率が向上します。
S2Hibernate.daoの機能を使用するにあたり、JavaBeans、Dao(.java)、diconファイルの作成が必要になります。
通常のJavaBeanを作成します。S2Hibernateを意識する必要はありませが、Hibernateで利用できるように記述してください。
S2hibernate.daoでは定数アノテーションという技術を使い、ソースコードにメタデータを記述するだけで動作するようになります。
Dao(Data Access Object)がどのJavaBeans(エンティティ)に関連付けられているのかはBEANアノテーションで指定します。
例えば、EmployeeDaoクラスがEmployeeエンティティに関連付けられる場合は次のように定義します。
public static final Class BEAN = Employee.class;
HQLアノテーションを使って、HQL文を指定して実行することができます。
public String getEmployeeByEname_ARGS = "employeeName";
public String getEmployeeByEname_HQL = "from Employee emp where emp.ename = :employeeName";
public List getEmployeeByEname(String employeeName);
ARGSアノテーションに合わせて、HQLに値を渡していきます。
Hibernateのマッピングファイルに記述したNamedQueryのname属性を次の様に指定します。
[Daoインターフェース名]+"_"+[メソッド名]
例)examples.hibernate.dao.EmployeeAutoDaoクラスのgetSQLEmployeeNameByIdメソッドで使うNamedQueryを指定する場合
<query name="examples.hibernate.dao.EmployeeAutoDao_getSQLEmployeeNameById"><![CDATA[
select emp.ename from Employee emp where emp.empno = :employeeId
]]></query>
メソッドの引数名をARGSアノテーションを使って指定します。メソッドの引数名は、リフレクションで取得できないためです。
public static final String getEmployee_ARGS = "empno";
public Employee getEmployee(int empno)
引数が複数ある場合には、カンマで区切ります。
※予約語
HQLアノテーション又は、NamedQueryを利用した検索を行う場合、ARGSアノテーションで次の2つが予約語なります。
"firstResult":検索結果の何レコード目から取得するか。
"maxResults":検索結果から、何件取得するか。
public String getEmployeeList_ARGS = "MaxResults";
public String getEmployeeList_HQL = "from Employee emp order by emp.empno";
public List getEmployeeList(int MaxResults);
S2hibernate.daoに自動的に検索処理を生成させることもできます。HQLアノテーションを指定せず、ARGSアノテーションを指定することで自動的に処理されます。
必要なのは次の定義だけです。
public static final String getEmployeeByJobDeptno_ARGS = "job, deptno";
public List getEmployeeByJobDeptno(String job, Integer deptno);
上の例の場合、次のHQL文として扱い":job",":empno"の部分に引数の値を渡します。
from Employee emp where emp.job = :job and emp.deptno = :deptno
S2hibernate.daoでは、引数がNullの場合、検索条件に含めません。この例で、deptnoがNullの場合の次の様なHQLに相当する処理を生成します
from Employee emp where emp.job = :job
「ARGSアノテーションを使っての検索の自動処理T」の自動処理がイコール("=")限定だったのに対して、
ARGSアノテーションの引数名の後ろに比較演算子を追加することで、指定した比較演算子を使っての比較が出来ます。
※利用できる演算子 : = ,> ,>= ,< ,<= ,like ,in
//ARGSアノテーションに比較オペレーター(>)を指定した場合
public String getEmployeeByGtSal_ARGS = "sal >";
public List getEmployeeByGtSal( BigDecimal sal );
上の例の場合、次のHQL文として扱い":sal"に引数の値を渡します。
from Employee emp where emp.sal > :sal
「ARGSアノテーションを使っての検索の自動処理T」と同様、引数がNullの場合、検索条件に含めません。
メソッドの引数にDTO(Data Transter Object)を使う場合、ARGSアノテーションせず、メソッドの引数をDTO1つにします。
HQL(HQLアノテーションまたは、NamedQuery)にDTOの値を渡す場合、
HQLの中の名前付き引数(変数名に":"つける)とDTOのプロパティ名をあわせることで、
メソッドの実行時に、HQLにDTOの値が渡されて実行されます。
HQL(HQLアノテーションまたは、NamedQuery)が指定されていないメソッドに対して、DTO利用した場合、DTOのプロパティ名から自動的に検索処理を行います。
イメージとしては、HibernteのExampleの様な機能になります。
渡されてたDTOのNullでないプロパティを検索条件にして、オブジェクトを検索します。
(nullでないもを検索条件にするので、プリミティブ型は想定していません。)
「DTO(Data Transter Object)を使って自動処理する場合T」の自動処理がイコール("=")限定だったのに対して、
PROPERTYアノテーションを指定することで、比較演算子を使っての比較が出来ます。
PROPERTYアノテーションは、DTOを使う場合のみに指定します。
記述する内容はARGSアノテーションにDTOのプロパティ名を追加した形式になります。
形式:[エンティティのプロパティ名]+" "+[演算子]+" "+[DTOのプロパティ名]
//ARGSアノテーションに比較オペレーター(>=,<=)を指定した場合(EmployeeSearchDto)
//指定したフィールドが指定した範囲の値のオブジェクトを取得したいとき
public String getEmployeeByDto_PROPERTY = "empno,ename,job,mgr,deptno," +
"hiredate >= fromHiredate,hiredate <= toHiredate,sal >= fromSal,sal <= toSal";
public List getEmployeeByDto( EmployeeSearchDto dto );
この例の場合、
"empno,ename,job,mgr,deptno"の部分に関しては、エンティティとDTOのプロパティ名が一致しているため、DTOのプロパティ名の記述が省略されています。また、演算子も=(イコール)を使うので省略されています。
次の3つはどれを記述しても同じ意味になります。
"empno,ename,job,mgr,deptno"
"empno =,ename =,job =,mgr =,deptno ="
"empno = empno,ename = ename,job = job,mgr = mgr,deptno = deptno"
"hiredate >= fromHiredate,hiredate <= toHiredate,sal >= fromSal,sal <= toSal"の部分に関しては、
BEANアノテーションに記述されているEmployeeクラスのhiredateプロパティが
DTOのfromHiredateプロパティの値以下であるという様な条件が4パターン記述されていることになります。
S2Hibernate.daoではメソッドのsignatureより処理を自動的に決定しています。
そのためメソッドのsignatureはS2hibetnate.daoの想定にあわせてもらう必要があります。
処理 |
メソッド名 |
備考 |
save |
insert,create,add,save ではじまる |
戻り値はvoidです。
引数の型はエンティティの型と一致させます。 |
update |
merge,update ではじまる |
戻り値はvoidです。
引数の型はエンティティの型と一致させます。
※ Hibernateのupdateは永続オブジェクトをHibernateのSessionに関連づけるメソッドです。 |
saveOrUpdate |
saveOrUpdateではじまる |
戻り値はvoidです。
引数の型はエンティティの型と一致させます。 |
load |
loadではじまる |
戻り値はObjectです。
引数の型は主キーカラム(id)の型と一致させます。 |
delete |
delete,removeではじまる |
戻り値はvoidです。
引数の型はエンティティの型と一致させます。 |
select |
上記に該当しない場合 |
・戻り値の型がjava.util.Listを実装している場合、検索結果のエンティティのリストを返します。
・戻り値の型がエンティティの型の場合、エンティティを返します。
・それ以外の場合、select count(emp) from Employee empのように1行で1のカラムの値を返すというようにS2Hibernate.daoは想定します。 |
※select時に実行するHQL文の優先順位
- HQLアノテーションを指定している場合、HQLアノテーションに記述したHQL文を実行します。
- Hibernateのマッピングファイルに[ Daoインターフェース名 + "_" +メソッド名 ] でNamedQueryが指定されていた場合、その指定されているクエリーを実行します。
- Hibernateのマッピングファイルに[ メソッド名 ] でNamedQueryが指定されていた場合、その指定されているクエリーを実行します。
- 上記に当てはまらない場合、ARGSアノテーションまたは、PROPERTYアノテーションを使って自動処理を行います。
- ARGSアノテーション、PROPERTYアノテーションの指定がない場合、BEANアノテーションで指定したエンティティすべてを含んだListを返します。
作成したDaoクラスを追加します。
s2hinernate.diconを追加します。
例)EmployeeAutoDao.dicon
s2hibernate.dicon
作成するファイは以下のとおりです。
通常のJavaBeanを作成します。S2Hibernateを意識する必要はありませがHibernateで利用できるように記述してください。
package examples.hibernate.entity;
import java.io.Serializable;
public class Employee implements Serializable {
private long empno;
private String ename;
private String job;
private Short mgr;
private java.util.Date hiredate;
private Float sal;
private Float comm;
private short deptno;
public Employee() {}
public Employee(long empno) { this.empno = empno; }
public long getEmpno() { return this.empno; }
public void setEmpno(long empno) { this.empno = empno; }
public java.lang.String getEname() { return this.ename; }
public void setEname(java.lang.String ename) { this.ename = ename; }
public java.lang.String getJob() { return this.job; }
public void setJob(java.lang.String job) { this.job = job; }
public Short getMgr() { return this.mgr; }
public void setMgr(Short mgr) { this.mgr = mgr; }
public java.util.Date getHiredate() { return this.hiredate; }
public void setHiredate(java.util.Date hiredate) { this.hiredate = hiredate; }
public Float getSal() { return this.sal; }
public void setSal(Float sal) { this.sal = sal; }
public Float getComm() { return this.comm; }
public void setComm(Float comm) { this.comm = comm;}
public short getDeptno() { return this.deptno; }
public void setDeptno(short deptno) { this.deptno = deptno; }
public boolean equals(Object other) {
if ( !(other instanceof Employee) ) return false;
Employee castOther = (Employee) other;
return this.getEmpno() == castOther.getEmpno();
}
public int hashCode() {
return (int) this.getEmpno();
}
}
通常のHibernateのマッピングファイルを作成します。S2Hibernateを意識する必要はありません。
<hibernate-mapping>
<class name="examples.hibernate.entity.Employee" table="EMP">
<id name="empno" column="EMPNO" type="long">
<generator class="assigned"/>
</id>
<property name="ename" column="ENAME" type="string" length="10"/>
<property name="job" column="JOB" type="string" length="9"/>
<property name="mgr" column="MGR" type="short" length="4"/>
<property name="hiredate" column="HIREDATE" type="timestamp"/>
<property name="sal" column="SAL" type="float" length="7"/>
<property name="comm" column="COMM" type="float" length="7"/>
<property name="deptno" column="DEPTNO" type="short" length="2"/>
</class>
</hibernate-mapping>
Dao用のインターフェースを宣言します。S2Hibernateを意識する必要はありません。
package examples.hibernate.dao;
import examples.hibernate.entity.Employee;
public interface EmployeeDao {
public Employee getEmployee(int empno);
}
Dao用の実装を記述します。
- S2SessionFactory型のフィールドを定義
- コンストラクタで、S2SessionFactoryを取得するように記述
- 各メソッドでS2SessionFactoryからS2Sessionを取得し、処理を記述する
package examples.hibernate.dao;
import java.util.List;
import net.sf.hibernate.Hibernate;
import org.seasar.hibernate.S2SessionFactory;
import examples.hibernate.entity.Employee;
public class EmployeeDaoImpl implements EmployeeDao {
private static final String HQL = "from Employee where empno = ?";
private S2SessionFactory sessionFactory_;
public EmployeeDaoImpl(S2SessionFactory sessionFactory) {
sessionFactory_ = sessionFactory;
}
public Employee getEmployee(int empno) {
List result = sessionFactory_.getSession().find(
HQL, new Integer(empno), Hibernate.INTEGER);
if (result.size() > 0) {
return (Employee) result.get(0);
} else {
return null;
}
}
}
作成したDaoクラスとorg.seasar.hibernate.impl.S2SessionFactoryImplを追加します。
<components>
<include path="j2ee.dicon"/>
<component class="org.seasar.hibernate.impl.S2SessionFactoryImpl"/>
<component class="examples.hibernate.dao.EmployeeDaoImpl">
<aspect>j2ee.requiredTx</aspect>
</component>
</components>
Daoを実行する基本的な方法は以下のようになります。
- 作成したdiconファイルのパスを引数にS2Containerを生成
- 生成したS2ContainerからgetComponentを呼び出し、登録したDaoを取得する
- 取得したDaoのメソッドを実行する
S2Hibernateではトランザクション制御は行なっていません、トランザクションについてはトランザクションの自動制御を参照して下さい。
実行クラスサンプル
package examples.hibernate.client;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
import examples.hibernate.service.EmployeeService;
public class EmployeeClient {
private static final String PATH =
"examples/hibernate/client/Employee.dicon";
public static void main(String[] args) {
S2Container container = S2ContainerFactory.create(PATH);/* 手順1 */
container.init();
try {
EmployeeService service =
(EmployeeService) container.getComponent(EmployeeService.class);/* 手順2 */
System.out.println(service.getEmployee(7788).getEname());/* 手順3 */
} finally {
container.destroy();
}
}
}
DEBUG 2004-04-07 18:53:52,511 [main] トランザクションを開始しました
2004/04/07 18:53:52 net.sf.hibernate.cfg.Environment <clinit>
情報: Hibernate 2.1.2
省略
DEBUG 2004-04-07 18:53:54,654 [main] 物理的なコネクションを取得しました
DEBUG 2004-04-07 18:53:54,744 [main] 論理的なコネクションを取得しました
Hibernate: select employee0_.EMPNO as EMPNO, employee0_.ENAME as ENAME, employee0_.JOB as JOB,
employee0_.MGR as MGR, employee0_.HIREDATE as HIREDATE, employee0_.SAL as SAL,
employee0_.COMM as COMM, employee0_.DEPTNO as DEPTNO from EMP employee0_ where (empno=? )
DEBUG 2004-04-07 18:53:55,605 [main] 論理的なコネクションを閉じました
DEBUG 2004-04-07 18:53:55,625 [main] トランザクションをコミットしました
SCOTT
DEBUG 2004-04-07 18:53:55,625 [main] 物理的なコネクションを閉じました
package examples.hibernate.dao;
import java.util.List;
import examples.hibernate.entity.Employee;
public interface EmployeeAutoDao {
public Class BEAN = Employee.class;
//追加、削除、更新、保存or更新をする場合
public void save(Employee employee);
public void delete(Employee employee);
public void update(Employee employee);
public void saveOrUpdate(Employee employee);
//HQLを指定しないで実行する場合
public String getEmployeeByEmpNo_ARGS = "empno";
public Employee getEmployeeByEmpNo(long empNo);
public String getEmployeeByJobDeptno_ARGS = "job, deptno";
public List getEmployeeByJobDeptno(String job, short deptno);
//HQLを指定して実行する場合
public String getHQLAllEmployee_HQL = "from Employee emp order by emp.empno";
public List getHQLAllEmployee();
//何も指定していない場合
public List getAllEmployee();
//firstResult,maxResultsを指定する場合
public String getEmployeeList_ARGS = "firstResult,maxResults";
public String getEmployeeList_HQL = "from Employee emp order by emp.empno";
public List getEmployeeList(int firstResult ,int MaxResults );
//戻り値がintの場合
public String getEmployeeCount_HQL = "select count(emp) from Employee emp";
public int getEmployeeCount();
//戻り値がStringの場合
public String getEmployeeNameById_HQL
= "select emp.ename from Employee emp where empno = :employeeId ";
public String getEmployeeNameById_ARGS = "employeeId";
public String getEmployeeNameById(Long employeeId);
//NamedQuery呼び出しを使う場合
//(Employee.hbm.xmlの"examples.hibernate.dao.EmployeeAutoDao_getEmployeeByJob"に対応)
public String getEmployeeByJob_ARGS = "job";
public List getEmployeeByJob(String job);
//NamedQueryで戻り値がStringになるようなSQL文を使う場合
//(Employee.hbm.xmlの"examples.hibernate.dao.EmployeeAutoDao_getSQLEmployeeNameById"に対応)
public String getSQLEmployeeNameById_ARGS = "employeeId";
public String getSQLEmployeeNameById(Long employeeId);
//NamedQueryで戻り値がLongになるようなSQL文を使う場合
//(Employee.hbm.xmlの"getSQLEmployeeIdByName"NamedQueryを実行)
public String getSQLEmployeeIdByName_ARGS = "employeeName";
public Long getSQLEmployeeIdByName(String employeeName);
}
S2Hibernate.daoを使うのに必要な設定をまとめた"s2hibernate.dicon"をインクルードします。
<components>
<include path="s2hibernate.dicon"/>
<component class="examples.hibernate.dao.EmployeeAutoDao">
<aspect>j2ee.requiredTx</aspect>
<aspect>s2hibernate.interceptor</aspect>
</component>
</components>
S2Hibernate.daoを使うのに必要な設定をまとめたdiconファイル
<components namespace="s2hibernate">
<include path="j2ee.dicon"/>
<component class="org.seasar.hibernate.impl.S2SessionFactoryImpl"/>
<component name="interceptor"
class="org.seasar.hibernate.dao.interceptors.S2HibernateDaoInterceptor"/>
</components>
diconファイル名以外は、S2Hibernateの基本的な使い方と同じ流れになります。
- 作成したdiconファイルのパスを引数にS2Containerを生成
- 生成したS2ContainerからgetComponentを呼び出し、登録したDaoを取得する
- 取得したDaoのメソッドを実行する
package examples.hibernate.client;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
import examples.hibernate.dao.EmployeeAutoDao;
import examples.hibernate.entity.Employee;
public class EmployeeAutoDaoClient {
private static final String PATH =
"examples/hibernate/client/EmployeeAutoDao.dicon";
public static void main(String[] args) {
S2Container container = S2ContainerFactory.create(PATH);/* 手順1 */
container.init();
try {
EmployeeAutoDao dao = (EmployeeAutoDao) container
.getComponent(EmployeeAutoDao.class);/* 手順2 */
Employee emp = new Employee();
emp.setEmpno( 7788);
emp.setEname("SCOTT");
emp.setDeptno((short)10);
dao.save( emp ); /* 手順3 */
} finally {
container.destroy();
}
}
}
実行結果
DEBUG 2004-11-11 19:01:50,163 [main] トランザクションを開始しました
INFO 2004-11-11 19:01:50,323 [main] Hibernate 2.1.6
省略
DEBUG 2004-11-11 19:01:51,545 [main] 物理的なコネクションを取得しました
DEBUG 2004-11-11 19:01:51,645 [main] 論理的なコネクションを取得しました
省略
Hibernate: insert into EMP (ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO, EMPNO)
values (?, ?, ?, ?, ?, ?, ?, ?)
省略
DEBUG 2004-11-11 19:01:52,025 [main] 論理的なコネクションを閉じました
DEBUG 2004-11-11 19:01:52,025 [main] トランザクションをコミットしました
DEBUG 2004-11-11 19:01:52,045 [main] 物理的なコネクションを閉じました
|
|
|
|
© Copyright The Seasar Project and the others 2004-2005, all rights reserved. |