はじめてのS2Dao.NET
S2Dao.NETはマッピング情報をXMLに記述しないO/Rマッピングフレームワークです。 S2Container.NET上で動作します。
マッピングのためにXMLをガリガリ書くのが面倒なので嬉しいところ。というわけで、Oracleに接続して単純なCRUDを行うサンプルを書いてみました。
先ずは対象となるテーブルから。
create table Greeting( id integer, message varchar (128) ); -- IDを主キーとする alter table Greeting add constraint Greeting_P primary key (id); -- シーケンスを作成する create sequence GreetingID;
主キーとメッセージだけの単純なテーブルです。これをSQL*Plusなどで実行してください。
次にテーブルのマッピング先となるクラスです。
using System; using Seasar.Dao.Attrs; // Entity [Table("Greeting")] public class Greeting { private int id; private string message; [ID ("sequence", "GreetingID")] public int ID { get { return id; } set { id = value; } } public string Message { get { return message; } set { message = value; } } public override string ToString () { return String.Format ("{0}:{1}", ID, Message); } }
Table/IDという属性がついている以外は普通のクラスですね。Table属性はデータベースのテーブル名を指定します。クラス名とテーブル名が同じ場合は不要だった気がしますが、自信が無かったため付けてしまいました。(^^; ID属性ではシーケンスを使うことと、そのときに使用するシーケンスオブジェクト名を指定しています。今回はS2Dao.NETに自動的にIDを付けさせますが、手動の場合はID属性は不要です。
さて、クラスとテーブルが出来ましたので次は両者のマッピングですが、DAO(Data Access Object)を作成します。作成と言っても実は、インタフェースを定義するだけで、実装はS2Dao.NETが勝手にやってくれます。AOP万歳。
で、そのDAOのインタフェースですが、
using System; using System.Collections; using Seasar.Dao.Attrs; [Bean (typeof (Greeting))] public interface IGreetingDao { int InsertGreeting (Greeting greeting); int UpdateGreeting (Greeting greeting); int DeleteGreeting (Greeting greeting); IList GetAllList (); [Query ("id=/*id*/")] Greeting GetGreetingByID (int id); }
こんな感じ。Bean属性で対象となるクラスを指定します。Insertクラス名/Updateクラス名/Deleteクラス名などのメソッド名はルールなので合わせてください。また、Query属性で指定した内容はwhere節に埋め込まれます。コメントとなっている変数にメソッドの引数が展開されます。
さて、準備は出来ましたのでDIしてみましょう。
構成ファイルは以下のようになります。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="seasar" type="Seasar.Framework.Xml.S2SectionHandler, Seasar" /> </configSections> <appSettings> <!-- oracleex.diconで使用 --> <add key="ConnectionString" value="Data Source=mydb;User Id=user;Password=pass;" /> </appSettings> <seasar> <assemblys> <assembly>Seasar.Dao</assembly> <assembly>System.Data.OracleClient, version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</assembly> </assemblys> </seasar> </configuration>
assemblyとしてSeasar.DaoとSystem.Data.OracleClientを追加します。また、appSettingsで接続文字列を設定してみました。
次に、app.diconファイルです。
<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components> <!-- S2Dao.NETでOracleに接続 --> <include path="OracleEx.dicon" /> <component class="IGreetingDao" name="dao"> <aspect>OracleEx.DaoInterceptor</aspect> </component> </components>
aspectで指定されているOracleEx.DaoInterceptorがミソで、コイツがIGreetingDaoインタフェースの実装を自動生成してくれます。
Oracleを使うにはもう少し設定が必要になりますが、OracleEx.diconの中にまとめてしまい、他からインクルードするだけになっています。OracleEx.diconはブラックボックスにしておいて問題ないと思いますが、一応、中身を見ておきましょう。
<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components namespace="OracleEx"> <!-- データプロバイダ --> <component name="Oracle" class="Seasar.Extension.ADO.DataProvider"> <property name="ConnectionType">"System.Data.OracleClient.OracleConnection"</property> <property name="CommandType">"System.Data.OracleClient.OracleCommand"</property> <property name="ParameterType">"System.Data.OracleClient.OracleParameter"</property> <property name="DataAdapterType">"System.Data.OracleClient.OracleDataAdapter"</property> </component> <!-- データソース --> <component name="SqlDataSource" class="Seasar.Extension.Tx.Impl.TxDataSource"> <property name="DataProvider">Oracle</property> <!-- 接続文字列は構成ファイルから取得 --> <property name="ConnectionString"> appSettings['ConnectionString']</property> </component> <!-- DaoInterceptor --> <component class="Seasar.Extension.ADO.Impl.BasicDataReaderFactory" /> <component class="Seasar.Extension.ADO.Impl.BasicCommandFactory" /> <component class="Seasar.Dao.Impl.DaoMetaDataFactoryImpl" /> <component name="DaoInterceptor" class="Seasar.Dao.Interceptors.S2DaoInterceptor"/> <!-- ローカルトランザクション用のインターセプター --> <component name="LocalRequiredTx" class="Seasar.Extension.Tx.TransactionInterceptor"> <arg><component class="Seasar.Extension.Tx.Impl.LocalRequiredTxHandler" /></arg> <property name="TransactionStateHandler">TransactionContext</property> </component> <!-- 分離レベルの指定 --> <component name="TransactionContext" class="Seasar.Extension.Tx.Impl.TransactionContext"> <property name="IsolationLevel">System.Data.IsolationLevel.ReadCommitted</property> </component> </components>
接続文字列を構成ファイルに出したので、あまり見ることはないでしょう。
準備も整ったので、これらを使ってOracleにアクセスしてみましょう。
using System; using System.Collections; using Seasar.Framework.Container; using Seasar.Framework.Container.Factory; public class App { public static void TestSelect (IGreetingDao dao) { IList list = dao.GetAllList (); if (list.Count > 0) foreach (Greeting g in dao.GetAllList ()) Console.WriteLine (g); else Console.WriteLine ("Greeting is empty."); } public static void TestInsert (IGreetingDao dao) { Console.WriteLine ("Insert"); Greeting entity = new Greeting (); entity.Message = "Hello"; dao.InsertGreeting (entity); entity.Message = "Goodby"; dao.InsertGreeting (entity); } public static void TestUpdate (IGreetingDao dao) { Console.WriteLine ("Update"); foreach (Greeting g in dao.GetAllList ()) { g.Message += ", World"; dao.UpdateGreeting (g); } } public static void TestDelete (IGreetingDao dao) { Console.WriteLine ("Delete"); foreach (Greeting g in dao.GetAllList ()) dao.DeleteGreeting (g); } public static void Main () { SingletonS2ContainerFactory.Init (); IS2Container container = SingletonS2ContainerFactory.Container; IGreetingDao dao = container.GetComponent (typeof(IGreetingDao)) as IGreetingDao; TestSelect (dao); TestInsert (dao); TestSelect (dao); TestUpdate (dao); TestSelect (dao); TestDelete (dao); TestSelect (dao); } } /* Greeting is empty. Insert 5:Hello 6:Goodby Update 5:Hello, World 6:Goodby, World Delete Greeting is empty. */
SQL無しでデータベースアクセスが出来るようになりましたね。