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点が必要になります。
また必要に応じて以下の機能を使用します。
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, 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, 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, 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
検索処理を行う場合は、上記のケース以外で戻り値の型を指定します。
- 戻り値の型が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を使用することも出来ます。
自動的に生成される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文", 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()
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ファイルが見つからない場合、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
注:現在はまだ結果セットを返す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 |
未確認 |
更新(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プロパティは永続化の対象になりません。
更新するときに、このプロパティだけをSQLに含めたいという場合もあります。
そのような場合はPersistentProps属性を使います。複数のプロパティを指定する場合はカンマで区切ります。
C#
[PersistentProps("Deptno")]
int Insert(Employee emp);
VB.NET
<PersistentProps("Deptno")> _
Function Insert(emp As Employee) As Integer
上記のように指定するとInsertメソッドで、プライマリキー, VersionNo, Timestampのプロパティに加えて、
PersistentProps属性で指定したプロパティが永続化の対象になります。
|