SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

S2Dao.NETでXMLレスなO/Rマッピングを行う

S2Dao.NETを用いて生産性・パフォーマンスの高いDaoを構築する


  • X ポスト
  • このエントリーをはてなブックマークに追加

(1)Entityの作成「Book.cs」

 まず最初に「Book.cs」というEntityを作成します。Entityとはレコードのデータを格納するクラスです。単純なプロパティから構成されます。

Book.cs(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では下表の属性を設定することが可能です。

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("結合元カラム名:結合先カラム名")]
注1
 S2Dao.NETではEntityクラスとテーブルに数値型(Int32)でVersionNoという名前のフィールドを定義するだけで自動的に番号を用いた排他制御を行います。
注2
 S2Dao.NETではEntityクラスとテーブルに日付時刻型(DateTime)でTimestampという名前のフィールドを定義するだけで自動的に時間を用いた排他制御を行います。

 Entityクラスに設定できる属性の詳細については、S2Dao.NETのドキュメントをご覧ください。

(2)Daoの作成「IBookDao.cs」

 続いて、「IBookDao.cs」という名前のDaoを作成します。Daoはデータベースを操作(INSERTUPDATEDELETESELECT)するインターフェイスです。インターフェイスのため実装はなく、宣言のみを記述します。

IBookDao.cs(Dao)
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では命名規約に沿ったメソッドを定義することによって、追加/更新/参照/削除の動作が決定します。

Daoのメソッドの命名規約と実行SQL
メソッド名対応するSQL戻り値引数
Insert*/Add*/Create*INSERT文Int32(更新件数)/voidEntityクラス
Update*/Modify*/Store*UPDATE文Int32(更新件数)/voidEntityクラス
Delete*/Remove*DELETE文Int32(更新件数)/voidEntityクラス
上記以外のメソッド名SELECT文Entityクラス/配列/IList/IList<Entity>(注3)自由
注3
 SELECT文の戻り値が、これらの型以外の場合は、SELECT文の結果の1行目/1カラム目の値を取得します。

 ここでは「int Insert(Book book)」というInsertから始まる名前のメソッドを宣言しています。そのため、このメソッドを呼び出すとSQLのINSERT文が自動的に生成され、実行されます。戻り値はint型(System.Int32型)のため、挿入した件数が設定されます。同様にUpdateDeleteから始まる名前のメソッドも宣言します。

SELECTを実行するメソッドの宣言

 INSERTUPDATEDELETEに該当したメソッド名ではない場合は、SELECT文を実行するメソッドになります。ここでは「Book[] GetAllBook()」と配列を戻すメソッドを宣言しているため、Entityのリストを返します(戻り値の型がIListインターフェイスの場合はEntityクラスのコレクションを複数件返し、Entityの場合はEntityを1件返します)。

 このように、S2Dao.NETでは命名規約や型に沿ったメソッドを定義することでデータベースにアクセスできるようになります。

SQLの細かい制御

 S2Dao.NETでは、SQLは自動生成されますが、細かい条件を制御することも可能です。ここでは、Sql属性を利用して、値段の平均値を求めるメソッドを定義しています。

IBookDao.cs(Dao)
[Sql("SELECT AVG(price) FROM book")]
int GetAvgPrice();

 Sql属性を利用すると、自動生成したSQLではなく、属性に定義したSQLをそのまま実行します。

SQLコメント

 WHERE句の部分だけを設定する場合は、Query属性を指定します。GetByTitleメソッドを呼び出すと、WHERE句にQuery属性に指定した条件が付加されます。

IBookDao.cs(Dao)
[Query("title LIKE /*book.Title*/")]
Book[] GetByTitle(Book book);

 S2Dao.NETでは、/*~*/構文を利用して、パラメータをバインドできます。ここでは、/*book.Title*/book変数のTitleプロパティをバインドしています。SQLのコメント形式を利用していることから「SQLコメント」とよびます。パラメータのバインド以外にも下表のSQLコメントが指定できます。

SQLコメントの種類
コメントの種類構文概要
バインド変数コメント/*引数名[.プロパティ名]*/プレースホルダでバインド
埋め込み変数コメント/*$引数名[.プロパティ名]*/文字列で埋め込み
IFコメント/*IF 条件*/.../*END*/条件に応じたSQL文の切替
BEGINコメント/*BEGIN*/WHERE/*END*/IFコメントの状態に応じたWHERE句の切替

 なお、本当にSQLのコメントを記述したい場合は、/* ~ */と「/*」の後ろに空白を入れます。SQLコメントの詳細についてはS2Dao.NETのドキュメントをご覧ください。

テキストファイルに記述したSQLの呼び出し

 S2Dao.NETでは、テキストファイルを用意し、それに記述されているSQL文を発行させることもできます。

IBookDao.cs(Dao)
Book[] GetBetweenPrice(int low,int high);

 IBookDao.csと同じ名前空間(フォルダ)に「インターフェイス名_メソッド名.sql」というファイルを用意すると、SQLを自動生成せずに、そのファイルに記述されたSQLを実行します。

IBookDao_GetBetweenPrice.sql(SQL)
SELECT ID, PRICE, TITLE FROM BOOK
WHERE PRICE BETWEEN /*low*/ AND /*high*/

 この仕組みを利用すると、C#(VB)の開発者とDBAによる分業が容易になります。

コラム:SQL実行環境とプログラムの両方で使用できる「2WaySQL」
 SQL Serverの管理ツール「SQL Server Management Studio」では、次のSQLを正常に実行できます。
SELECT * FROM BOOK WHERE PRICE BETWEEN /*low*/2000 AND /*high*/3000
 しかも、このSQLは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インターフェイスでは下表の属性を設定することが可能です。

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のドキュメントをご覧ください。

次のページ
(3)設定ファイルを作る「Dao.dicon」

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 青木 淳夫(アオキ アツオ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/805 2007/04/13 13:05

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング