(1)Entityの作成「Book.cs」
まず最初に「Book.cs」というEntityを作成します。Entityとはレコードのデータを格納するクラスです。単純なプロパティから構成されます。
using System; using Seasar.Dao.Attrs; //S2Dao.NETの属性を使用 namespace S2DaoSample.Entity { /// <summary> /// Bookエンティティ(書籍データを格納する入れ物) /// </summary> public class Book { private int _id; private string _title; private int _price; private DateTime _editdate; //ID public int Id { get { return _id; } set { _id = value; } } //タイトル public string Title { get { return _title; } set { _title = value; } } //価格 public int Price { get { return _price; } set { _price = value; } } //更新日 [Column("EDIT_DATE")] //プロパティとカラム名が異なるときに指定 public DateTime Editdate { get { return _editdate; } set { _editdate = value; } } } }
カラムのマッピング
他のO/RマッピングツールではマッピングルールをXMLに定義しますが、S2Dao.NETでは、クラスやプロパティの上部に記述する属性(C#は[]
記号、VBでは<>
記号)によって指定できます。この属性は、Seasar.Dao.Attrs名前空間に存在します。
ここでは、クラスのプロパティ名(editdate
)とテーブルのカラム名(EDIT_DATE
)が異なるため、「[Column("EDIT_DATE")]
」と宣言して、「クラスのプロパティ」と「テーブルのカラム」をマッピングしています。
Entityクラスに設定できる属性
このサンプルでは、Column
属性を利用しましたが、Entityでは下表の属性を設定することが可能です。
属性 | 対象 | 意味 | 文例 |
Table | クラス | テーブルとの関連付け | [Table("対象テーブル名")] |
Column | プロパティ | カラムとの関連付け | [Column("対象カラム名")] |
ID | プロパティ | IDの自動生成方法(DB自動生成|SEQUENCE|手動設定) | ID("identity|sequence,名前|assigned") |
NoPersistentProps | クラス | データベースアクセスに使用しない(永続化しない)カラムの指定 | [NoPersistentProps("プロパティ名1", "プロパティ名2" ...)] |
VersionNoProperty | クラス | 排他制御用の列名を設定したい場合に指定(注1) | [VersionNoProperty("排他制御用プロパティ名")] |
TimestampProperty | クラス | 排他制御用の列名を設定したい場合に指定(注2) | [TimestampProperty("排他制御用プロパティ名")] |
Relno/Relkeys | プロパティ | N:1マッピング(左外部結合) | [Relno(0から始まる連番),Relkeys("結合元カラム名:結合先カラム名")] |
VersionNo
という名前のフィールドを定義するだけで自動的に番号を用いた排他制御を行います。Timestamp
という名前のフィールドを定義するだけで自動的に時間を用いた排他制御を行います。Entityクラスに設定できる属性の詳細については、S2Dao.NETのドキュメントをご覧ください。
(2)Daoの作成「IBookDao.cs」
続いて、「IBookDao.cs」という名前のDaoを作成します。Daoはデータベースを操作(INSERT
、UPDATE
、DELETE
、SELECT
)するインターフェイスです。インターフェイスのため実装はなく、宣言のみを記述します。
using System; using Seasar.Dao.Attrs; //S2Dao.NETの属性を使用 using S2DaoSample.Entity; namespace S2DaoSample.Dao { /// <summary> /// BookテーブルにアクセスするためのDao /// </summary> [Bean(typeof(Book))] //対応するEntityを指定 public interface IBookDao{ //全件取得 Book[] GetAllBook(); //INSERT int Insert(Book book); //UPDATE int Update(Book book); //DELETE int Delete(Book book); //価格平均をSELECT(SQL全文を記述) [Sql("SELECT AVG(price) FROM book")] int GetAvgPrice(); //タイトルによるLike検索(WHERE句を付加) [Query("title LIKE /*book.Title*/")] Book[] GetByTitle(Book book); //外部ファイル(IBookDao_GetBetweenPrice.sql)のSQLを実行 Book[] GetBetweenPrice(int low, int high); } }
関連するEntityの指定
DaoとEntityは「1:1」の関係になるため、「[Bean(typeof(Book))]
」と記述してIBookDao.csに対応するEntityがBook
であることを宣言しています。
INSERT/UPDATE/DELETEを実行するメソッドの宣言
S2Dao.NETでは命名規約に沿ったメソッドを定義することによって、追加/更新/参照/削除の動作が決定します。
メソッド名 | 対応するSQL | 戻り値 | 引数 |
Insert*/Add*/Create* | INSERT文 | Int32(更新件数)/void | Entityクラス |
Update*/Modify*/Store* | UPDATE文 | Int32(更新件数)/void | Entityクラス |
Delete*/Remove* | DELETE文 | Int32(更新件数)/void | Entityクラス |
上記以外のメソッド名 | SELECT文 | Entityクラス/配列/IList/IList<Entity>(注3) | 自由 |
ここでは「int Insert(Book book)
」というInsert
から始まる名前のメソッドを宣言しています。そのため、このメソッドを呼び出すとSQLのINSERT
文が自動的に生成され、実行されます。戻り値はint型(System.Int32型)のため、挿入した件数が設定されます。同様にUpdate
、Delete
から始まる名前のメソッドも宣言します。
SELECTを実行するメソッドの宣言
INSERT
/UPDATE
/DELETE
に該当したメソッド名ではない場合は、SELECT
文を実行するメソッドになります。ここでは「Book[] GetAllBook()
」と配列を戻すメソッドを宣言しているため、Entityのリストを返します(戻り値の型がIListインターフェイスの場合はEntityクラスのコレクションを複数件返し、Entityの場合はEntityを1件返します)。
このように、S2Dao.NETでは命名規約や型に沿ったメソッドを定義することでデータベースにアクセスできるようになります。
SQLの細かい制御
S2Dao.NETでは、SQLは自動生成されますが、細かい条件を制御することも可能です。ここでは、Sql
属性を利用して、値段の平均値を求めるメソッドを定義しています。
[Sql("SELECT AVG(price) FROM book")] int GetAvgPrice();
Sql
属性を利用すると、自動生成したSQLではなく、属性に定義したSQLをそのまま実行します。
SQLコメント
WHERE句の部分だけを設定する場合は、Query
属性を指定します。GetByTitleメソッドを呼び出すと、WHERE句にQuery
属性に指定した条件が付加されます。
[Query("title LIKE /*book.Title*/")]
Book[] GetByTitle(Book book);
S2Dao.NETでは、/*~*/
構文を利用して、パラメータをバインドできます。ここでは、/*book.Title*/
にbook
変数のTitle
プロパティをバインドしています。SQLのコメント形式を利用していることから「SQLコメント」とよびます。パラメータのバインド以外にも下表のSQLコメントが指定できます。
コメントの種類 | 構文 | 概要 |
バインド変数コメント | /*引数名[.プロパティ名]*/ | プレースホルダでバインド |
埋め込み変数コメント | /*$引数名[.プロパティ名]*/ | 文字列で埋め込み |
IFコメント | /*IF 条件*/.../*END*/ | 条件に応じたSQL文の切替 |
BEGINコメント | /*BEGIN*/WHERE/*END*/ | IFコメントの状態に応じたWHERE句の切替 |
なお、本当にSQLのコメントを記述したい場合は、/* ~ */
と「/*」の後ろに空白を入れます。SQLコメントの詳細についてはS2Dao.NETのドキュメントをご覧ください。
テキストファイルに記述したSQLの呼び出し
S2Dao.NETでは、テキストファイルを用意し、それに記述されているSQL文を発行させることもできます。
Book[] GetBetweenPrice(int low,int high);
IBookDao.cs
と同じ名前空間(フォルダ)に「インターフェイス名_メソッド名.sql
」というファイルを用意すると、SQLを自動生成せずに、そのファイルに記述されたSQLを実行します。
SELECT ID, PRICE, TITLE FROM BOOK WHERE PRICE BETWEEN /*low*/ AND /*high*/
この仕組みを利用すると、C#(VB)の開発者とDBAによる分業が容易になります。
SELECT * FROM BOOK WHERE PRICE BETWEEN /*low*/2000 AND /*high*/3000
Sql
属性や外部SQLファイルに指定しても正常に実行できます。これは、SQL実行環境では「
SELECT * FROM Book WHERE PRICE BETWEEN 2000 AND 3000
」と解釈され、S2Dao.NETでは「SELECT * FROM BOOK WHERE PRICE BETWEEN @low AND @high
」と解釈されるためです。このように1つのSQLをシームレスに2つの環境で利用することができることから、この機能は「2WaySQL」とよばれています。Daoインターフェイスに設定できる属性
このサンプルでは、Sql
属性とQuery
属性を利用しましたが、Daoインターフェイスでは下表の属性を設定することが可能です。
属性 | 対象 | 意味 | 文例 |
Query | メソッド | 自動生成SELECT文にWHERE句やORDER BY句を追加 | [Query("WHERE句 ORDER句")] |
Sql | メソッド | Sqlを記述 | [Sql("SQL文")] |
Procedure | メソッド | StoredProcedureを記述 | [Procedure("ストアドプロシージャ名")] |
NoPersistentProps | メソッド | 自動生成UPDATE文の更新しないプロパティを指定 | [NoPersistentProps("プロパティ名1", "プロパティ名2" ...)] |
PersistentProps | メソッド | 自動生成UPDATE文の更新するプロパティを指定 | [PersistentProps("プロパティ名1", "プロパティ名2" ...)] |
Daoインターフェイスに設定できる属性の詳細については、S2Dao.NETのドキュメントをご覧ください。