Seasar - DI Container with AOP -
Seasar DI Container with AOP
S2Dao.NET TOPページへ

S2Dao.NET - Daoインターフェース

Dao(Data Access Object)はインターフェースとして作成します。Entityに永続化するデータを格納し、Daoが永続化を行います。 Entityとは1:1の関係にあるので、1つのEntityクラスに対して1つのDaoインターフェースを作成することになります。 Daoのメソッドを呼ぶことによりメソッドに対応したSQLを実行します。SQLは自動生成や部分的に自動生成、 もしくはSQLファイルに記述されているものが実行されます。

Daoインターフェースで使用する属性はSeasar.Dao.Attrs名前空間にあります。 Daoインターフェースには以下の2点が必要になります。

また必要に応じて以下の機能を使用します。

Bean属性

DaoインターフェースがどのEntityクラスに関連付けられているのかをBean属性で指定します。 Entity属性ではなくBean属性である理由はJavaのS2Daoと統一しているためです。

IEmployeeDaoインターフェースがEmployeeエンティティに関連付けられている場合は、次のように定義します。

C#
[Bean(typeof(Employee))]
public interface IEmployeeDao
VB.NET
<Bean(GetType(Employee))> _
Public Interface IEmployeeDao

メソッドを定義する

Daoインターフェースに定義したメソッドを呼ぶことによりメソッドに対応したSQLが実行されますが、 更新処理(INSERT, UPDATE, DELETE)、検索処理毎にメソッドの命名規則があります。 S2Dao.NETではメソッドの命名規則よりSQL文の種類を自動的に判別しています。 また、定義するメソッドのオーバーロードはサポートしていません。

INSERT処理とINSERT文の自動生成

INSERT処理を行うメソッドの名前は、Insert, Add, Createのいずれかから始まる必要があります。 戻り値はvoid(VB.NETではSub)あるいはSystem.Int32(C#はint, VB.NETはInteger)を指定して下さい。 System.Int32の場合、更新した行数が戻り値となります。引数の型はEntityの型と一致させます。

特に属性やSQLファイルを用意していない場合は、自動的にINSERT文が生成され実行されます。

メソッドの定義例は以下のようになります。

C#
void Insert(Employee employee);
int AddEmp(Employee employee);
void CreateEmployee(Employee employee);
VB.NET
Sub Insert(employee As Employee)
Function AddEmp(employee As Employee) As Integer
Sub CreateEmployee(employee As Employee)

UPDATE処理とUPDATE文の自動生成

UPDATE処理を行うメソッドの名前は、Update, Modify, Storeのいずれかから始まる必要があります。 戻り値はvoid(VB.NETではSub)あるいはSystem.Int32(C#はint, VB.NETはInteger)を指定して下さい。 System.Int32の場合、更新した行数が戻り値となります。引数の型はEntityの型と一致させます。

特に属性やSQLファイルを用意していない場合は、自動的にUPDATE文が生成され実行されます。 WHERE句はプライマリキーから作成されます。

メソッドの定義例は以下のようになります。

C#
void Update(Employee employee);
int ModifyEmp(Employee employee);
void StoreEmployee(Employee employee);
VB.NET
Sub Update(employee As Employee)
Function ModifyEmp(employee As Employee) As Integer
Sub StoreEmployee(employee As Employee)

DELETE処理とDELETE文の自動生成

DELETE処理を行うメソッドの名前は、Delete, Removeのいずれかから始まる必要があります。 戻り値はvoid(VB.NETではSub)あるいはSystem.Int32(C#はint, VB.NETはInteger)を指定して下さい。 System.Int32の場合、更新した行数が戻り値となります。引数の型はEntityの型と一致させます。

特に属性やSQLファイルを用意していない場合は、自動的にDELETE文が生成され実行されます。 WHERE句はプライマリキーから作成されます。

メソッドの定義例は以下のようになります。

C#
void Delete(Employee employee);
int RemoveEmp(Employee employee);
VB.NET
Sub Delete(employee As Employee)
Function RemoveEmp(employee As Employee) As Integer

検索(SELECT)処理とSELECT文の自動生成

検索処理を行う場合は、上記のケース以外で戻り値の型を指定します。

  • 戻り値の型がSystem.Collections.IListの場合は、 SELECT文でエンティティのリスト(System.Collections.ArrayList)を返します。
  • 戻り値の型がSystem.Collections.Generic.IList<Entity型>の場合は、 SELECT文でエンティティのリスト(System.Collections.List<Entity型>)を返します。
  • 戻り値がエンティティ型の配列である場合は、エンティティ配列を返します。
  • 戻り値の型がエンティティの型の場合は、エンティティを返します。
  • 戻り値の型がDataTable型の場合はDataTable型を返します。
    型付きのDataTableの場合は型付きのDataTable型を返します。
    (S2Dao.NET 1.3.2以降)
  • 戻り値の型がDataSet(型付き含む)型の場合はDataSet(型付きであれば型付きDataSet)型を返します。
    型付きのDataSetの場合は型付きのDataSet型を返します。
    (S2Dao.NET 1.3.2以降)
    ※DataSet内にDataTableが一つだけ存在している場合のみを想定しています。
  • それ以外の場合は、SELECT count(*) FROM empのように1行1カラムの値を返すというようにS2Dao.NETは想定します。

特に属性やSQLファイルが用意されていない場合は、全てのカラムを全行取得するSELECT文が自動生成され実行されます。

メソッドのsignature(引数の値や型)からWHERE句を自動生成する

属性やSQLファイルが用意されていなくてもメソッドのsignature(引数の値や型)から、S2Dao.NETにWHERE句を自動生成させることもできます。 引数の型には組み込み型の他に、.NET 2.0からのnull許容型(System.Nullable構造体)、System.Data.SqlTypes名前空間のデータ型を指定することも出来ます。

SELECT * FROM emp
/*BEGIN*/WHERE
  /*IF job != null*/job = /*job*/'CLERK'/*END*/
  /*IF deptno.HasValue == true*/AND deptno = /*deptno*/20/*END*/
/*END*/

上記SQL文に相当するSQL文を自動生成するには以下のようにメソッドを定義します。上記SQLの/**/等の記法については、 SQLコメントのドキュメントを参照して下さい。

C#
IList GetEmployeeByJobDeptno(string job, int? deptno);
VB.NET
Function GetEmployeeByJobDeptno(job As String, deptno As Nullable(Of Int32)) As IList

N:1でマッピングされているカラムを指定する場合には、「カラム名_Relno属性で指定した番号」で指定します。 N:1でマッピングされているEntityは左外部結合を使って1つのSQL文で取得されます。左外部結合をサポートしていないRDBMSはSELECT文自動生成の対象外です。 オラクルのように左外部結合が標準と異なる場合も、S2Dao.NETがRDBMSの種類を自動的に判断して適切なSQL文を組み立てます。

DTOからWHERE句を自動生成する

引数にDTO(Data Transfer Object)を指定することも出来ます。DTOのプロパティを使って自動的にSQL文を組み立てます。 プロパティ名とカラム名が異なる場合は、Column属性を使ってカラム名を指定します。N:1マッピングされているカラムを指定する場合には、 「カラム名_Relno属性で指定した番号」で指定します。テーブルに存在しないプロパティ(カラム)は自動的に無視されます。 プロパティの値によって、WHERE句が変わるような動的SQL文を自動生成します。 動的SQL文の自動生成とORDER BY句ではじまるQuery属性は併用することが出来ます。

C#
public class EmployeeSearchCondition
{
    ・・・省略
   public string Job
   {
      set { _job = value; }
      get { return _job; }
   }

   [Column("dname_0")]
   public string Dname
   {
      set { _dname = value; }
      get { return _dname; }
   }
   ・・・省略
}
IList GetEmployeeBySearchCondition(EmployeeSearchCondition dto);
VB.NET
Public Class EmployeeSearchCondition
   ・・・省略
   Public Property Job() As String
      Get
         Return _job
      End Get
      Set
         _job = value
      End Set
   End Property

   <Column("dname_0")>  _
   Public Property Dname() As String
      Get
         Return _dname
      End Get
      Set
         _dname = value
      End Set
   End Property
   ・・・省略
End Class
Function GetEmployeeBySearchCondition(dto As EmployeeSearchCondition) As IList

また同様の指定方法で引数にEntityを使用することも出来ます。

Query属性 - 自動生成SELECT文にWHERE句やORDER BY句を追加する

自動的に生成されるSELECT文にWHERE句やORDER BY句を追加するには、Query属性を使用します。 Query属性は以下の形式でメソッドに指定します。

[Query("WHERE句 ORDER BY句")]

引数で給与の上限と下限を指定し、その間に含まれる従業員を抽出する場合は次のようにします。

C#
[Query("sal BETWEEN /*minSal*/ AND /*maxSal*/ ORDER BY empno")]
IList GetEmployeesBySal(float minSal, float maxSal);
VB.NET
<Query("sal BETWEEN /*minSal*/ AND /*maxSal*/ ORDER BY empno")> _
Function GetEmployeesBySal(minSal As Single, maxSal As Single) As IList

上記例の"/*変数名*/"をバインド変数コメントと言います。 バインド変数コメントをQuery属性に記述することにより、バインド変数コメントの変数名と同じ引数名の引数の値が、バインド変数コメントの部分に代入されます。 WHERE句から記述する場合はWHEREは省略できます。ORDER BY句だけを記述する場合はORDER BYで始めて下さい。

Query属性には他のSQLコメントも記述することが出来ます。 また引数にDTOを使用することも出来ます。

C#
[Query("job=/*dto.Job*/'CLERK' /*IF dto.Deptno.IsNull==false*/ AND deptno=/*dto.Deptno*/20/*END*/")]
IList GetEmployees(SearchCondition dto);
VB.NET
<Query("job=/*dto.Job*/'CLERK' /*IF dto.Deptno.IsNull==false*/ AND deptno=/*dto.Deptno*/20/*END*/")> _
Function GetEmployees(dto As SearchCondition) As IList

上記サンプルは引数dtoのプロパティDeptnoがnull出ない場合、deptnoがDeptnoプロパティの値と一致するという条件を追加します。 上記サンプルのDeptnoプロパティはSystem.Data.SqlTypes.SqlInt32型を使用しています。 SQLコメントについての詳しい説明は、SQLコメントを参照して下さい。

Sql属性 - Sqlを記述する

Sql属性の機能はSQLファイルと同様で、属性にてSQLおよびSQLコメントを使用することが可能です。 Sql属性は以下の形式でメソッドに指定します。

[Sql("SQL文")] または [Sql("SQL文", Seasar.Dao.KindOfDbms)]

C#
[Sql("SELECT empno,ename from emp where job=/*job*/ order by empno")]
Employee[] GetByJob(string job);
VB.NET
<Sql("SELECT empno,ename from emp where job=/*job*/ order by empno")> _
Function GetByJob(job As String) As Employee()

Sql属性の複数DBMS対応

DBMS毎に使用するSql属性を指定することができます。どのDBMSを使っているのかは、 Diconファイルに登録されているデータプロバイダとS2Dao.NETが持っているDbms.resxからS2Dao.NETが自動的に判断しています。 DBMS毎にSql属性を用意する場合は、Sql属性の第2引数にSeasar.Dao.KindOfDbms列挙型でDBMSを指定します。 KindOfDbms列挙型は以下の列挙子を持っています。

列挙子 DBMS
None DBMS指定無し
MSSQLServer MSSQLServer
DB2 DB2
MySQL MySQL
Oracle Oracle
PostgreSQL PostgreSQL
Firebird Firebird
MDB MDB(Access)

SqlFile属性 - Sqlファイルを明示的を指定する(バージョン1.3.5以降)

引数なしのSqlFile属性をメソッドに指定した場合、対応するSQLファイルが見つからない場合、S2Dao.NETが例外を返します。

引数ありのSqlFile属性をメソッドに指定した場合、対応するSQLファイルのパスを明示的に指定することが可能です。

SqlFile属性は以下の形式でメソッドに指定します。

[SqlFile] または [SqlFile("SQLファイルパス")]

C#
[SqlFile]
int GetCount();

[SqlFile("Seasar.Tests.Dao.Impl.SqlFile.GetCount.sql")]
int GetCount2();
VB.NET
<SqlFile()> _
Function GetCount() As Integer

<SqlFile("Seasar.Tests.Dao.Impl.SqlFile.GetCount.sql")> _
Function GetCount2() As Integer

Procedure属性 - StoredProcedureを記述する

注:現在はまだ結果セットを返すStoredProcedure、またメソッド引数や返値にDTOクラスを用いることに対応していません。

Procedure属性は実行するStoredProcedureやStoredFunctionを指定することです。実際にはProcedure属性を指定するだけではなく、StoredProcedureのパラメータに対応するメソッドの引数が必要です。Procedure属性は以下の形式でメソッドに指定します。

[Procedure("ストアドプロシージャ名")] または[Procedure("スキーマ名.ストアドプロシージャ名")]

C#
[Procedure("SP_EMP")]
int GetByJob(string job, out string name);
VB.NET
<Procedure("SP_EMP")> _
Function GetByJob(job As String, ByRef name As String) As Integer

引数名にはStoredProcedureのパラメータ名を指定します。その引数にC#でいうところのoutを指定するとストアドプロシージャのOutputパラメータに対応し、refであればInput/Outputパラメータに対応します。何も指定しなければInputパラメータに対応します。

ストアドプロシージャがReturn句による値を返さないときはメソッドの返値にvoidを指定します。値を返すときは対応する型を指定します。Firebirdのように複数の値を返せるときはHashtableを指定します。

Procedure属性のDBMS対応

現在、動作を確認しているのは次の通りです。

DBMS 制限事項
MS SQLServer Input, Output, Input/Output, Returnは一つの数値のみ(仕様)
DB2 未確認
MySQL 未確認
Oracle Input, Output, Input/Output, Returnは一つ
PostgreSQL 未確認
Firebird Input, 複数のReturn(実際にはOutputなのでout指定可能)
MDB 未確認

NoPersistentProps属性 - 自動生成UPDATE文の更新しないプロパティを指定する

更新(Insert, Update)するときに、このプロパティはSQLに含めて欲しくないという場合があります。 そのような場合はNoPersistentProps属性を使います。複数のプロパティを指定する場合はカンマで区切ります。

C#
[NoPersistentProps("Sal", "Comm")]
int Insert(Employee emp);
VB.NET
<NoPersistentProps("Sal", "Comm")> _
Function Insert(emp As Employee) As Integer

上記のように指定すると、InsertメソッドでSalとCommプロパティは永続化の対象になりません。

PersistentProps属性 - 自動生成UPDATE文の更新するプロパティを指定する

更新するときに、このプロパティだけをSQLに含めたいという場合もあります。 そのような場合はPersistentProps属性を使います。複数のプロパティを指定する場合はカンマで区切ります。

C#
[PersistentProps("Deptno")]
int Insert(Employee emp);
VB.NET
<PersistentProps("Deptno")> _
Function Insert(emp As Employee) As Integer

上記のように指定するとInsertメソッドで、プライマリキー, VersionNo, Timestampのプロパティに加えて、 PersistentProps属性で指定したプロパティが永続化の対象になります。