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

SQLは自由に発行したい。でもADO.NETを使うのはめんどくさい。そんなあなたのために用意されているのが、S2ADOです。

データ操作

検索処理(BeanList)

さっそく複数件のobjectを検索してみましょう。検索するためにはBasicSelectHandlerを使います。次のようなプロパティが用意されています。

Seasar.Extension.ADO.Impl.BasicSelectHandler

プロパティ 説明 S2Containerでの設定例
DataSource DataSource 通常自動的に設定されます。
Sql 実行したいSQL文 "SELECT * FROM emp"
DataReaderHandler System.Data.IDataReaderを処理するHandlerのクラス 複数件のobjectを返すためにはBeanListDataReaderHandlerを使います。
<component
  class="Seasar.Extension.ADO.Impl.BeanListDataReaderHandler">
  <arg>Seasar.Examples.Reference.ADO.Employee</arg>
</component>

CommandTimeout コマンドが実行されるまでの待機時間(秒)。-1の場合は特に設定は行われない。  

Seasar.Examples.Reference.ADO.SelectBeanList.dicon

<components>
  <include path="Seasar.Examples/Ado.dicon" />
  <component name="SelectBeanListClient" class="Seasar.Examples.Reference.ADO.SelectBeanListClient"/>
  <component name="SelectBeanListHandler" class="Seasar.Extension.ADO.Impl.BasicSelectHandler">
    <property name="Sql">
"SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno FROM emp"</property> <property name="DataReaderHandler"> <component class="Seasar.Extension.ADO.Impl.BeanListDataReaderHandler"> <arg>Seasar.Examples.Reference.ADO.Employee</arg> </component> </property> </component> </components>

Seasar.Examples.Reference.ADO.SelectBeanListClient

C#
using System;
using System.Collections;
using Seasar.Extension.ADO;
using Seasar.Framework.Container;
using Seasar.Framework.Container.Factory;

namespace Seasar.Examples.Reference.ADO
{
    public class SelectBeanListClient
    {
        private const string PATH = "Seasar.Examples/Reference/ADO/SelectBeanList.dicon";

        public void Main()
        {
            IS2Container container = S2ContainerFactory.Create(PATH);
            container.Init();
            try
            {
                ISelectHandler handler =
                    (ISelectHandler) container.GetComponent("SelectBeanListHandler");
                IList result = (IList) handler.Execute(null);
                for (int i = 0; i < result.Count; ++i)
                {
                    Console.Out.WriteLine(result[i]);
                }
            }
            finally
            {
                container.Destroy();
            }
        }
    }
}

実行結果

DEBUG 2006-06-19 23:26:59,890 [9] 論理的なコネクションを取得しました
DEBUG 2006-06-19 23:26:59,984 [9] 論理的なコネクションを閉じました
7369, SMITH, CLERK, 7902, 1980/12/17 0:00:00, 800, , 20, 
7499, ALLEN, SALESMAN, 7698, 1981/02/20 0:00:00, 1600, 300, 30, 
7521, WARD, SALESMAN, 7698, 1981/02/22 0:00:00, 1250, 500, 30, 
7566, JONES, MANAGER, 7839, 1981/04/02 0:00:00, 2975, , 20, 
7654, MARTIN, SALESMAN, 7698, 1981/09/28 0:00:00, 1250, 1400, 30, 
7698, BLAKE, MANAGER, 7839, 1981/05/01 0:00:00, 2850, , 30, 
7782, CLARK, MANAGER, 7839, 1981/06/09 0:00:00, 2450, , 10, 
7788, SCOTT, ANALYST, 7566, 1982/12/09 0:00:00, 3000, , 20, 
7839, KING, PRESIDENT, , 1981/11/17 0:00:00, 5000, , 10, 
7844, TURNER, SALESMAN, 7698, 1981/09/08 0:00:00, 1500, 0, 30, 
7876, ADAMS, CLERK, 7788, 1983/01/12 0:00:00, 1100, , 20, 
7900, JAMES, CLERK, 7698, 1981/12/03 0:00:00, 950, , 30, 
7902, FORD, ANALYST, 7566, 1981/12/03 0:00:00, 3000, , 20, 
7934, MILLER, CLERK, 7782, 1982/01/23 0:00:00, 1300, , 10, 

バインド変数がある場合には、Execute(object[])の引数に指定します。今回の例はバインド変数がないので、nullを設定しています。S2Containerにコンポーネントを組み立ててもらい、後はExecute()を呼び出すだけなので楽チンです。カラム名にアンダースコア(_)が含まれている場合は、アンダースコアを除いてプロパティにマッピングされます。

検索処理(Bean)

1件のobjectを検索するためには上記と同様にBasicSelectHandlerを使います。BeanDataReaderHandlerを使うこと以外は上記と同様です。結果はリストではなくobjectとしてかえってきます。

Seasar.Examples.Reference.ADO.SelectBean.dicon

<components>
  <include path="Seasar.Examples/Ado.dicon" />
  <component name="SelectBeanClient" class="Seasar.Examples.Reference.ADO.SelectBeanClient"/>
  <component name="SelectBeanHandler" class="Seasar.Extension.ADO.Impl.BasicSelectHandler">
    <property name="Sql">
"SELECT empno, ename, job, mgr, hiredate, sal, comm,
deptno FROM emp WHERE empno = @empno"</property> <property name="DataReaderHandler"> <component class="Seasar.Extension.ADO.Impl.BeanDataReaderHandler"> <arg>Seasar.Examples.Reference.ADO.Employee</arg> </component> </property> </component> </components>

Seasar.Examples.Reference.ADO.SelectBeanClient

C#
using System;
using Seasar.Extension.ADO;
using Seasar.Framework.Container;
using Seasar.Framework.Container.Factory;

namespace Seasar.Examples.Reference.ADO
{
    public class SelectBeanClient
    {
        private const string PATH = "Seasar.Examples/Reference/ADO/SelectBean.dicon";

        public void Main()
        {
            IS2Container container = S2ContainerFactory.Create(PATH);
            container.Init();
            try
            {
                ISelectHandler handler = (ISelectHandler) container.GetComponent("SelectBeanHandler");
                Employee result = (Employee) handler.Execute(new object[] { 7788 });
                Console.Out.WriteLine(result);
            }
            finally
            {
                container.Destroy();
            }
        }
    }
}

実行結果

DEBUG 2006-06-19 23:34:54,234 [9] 論理的なコネクションを取得しました
DEBUG 2006-06-19 23:34:54,249 [9] 論理的なコネクションを閉じました
7788, SCOTT, ANALYST, 7566, 1982/12/09 0:00:00, 3000, , 20, 

検索処理(DictionaryList)

複数件のDictionaryを取得することもできます。DataReaderHandlerにはDictionaryListDataReaderHandlerを使います。

Seasar.Examples.Reference.ADO.SelectDictionaryList.dicon

<components>
  <include path="Seasar.Examples/Ado.dicon" />
  <component name="SelectDictionaryListClient" 
class="Seasar.Examples.Reference.ADO.SelectDictionaryListClient"/> <component name="SelectDictionaryListHandler"
class="Seasar.Extension.ADO.Impl.BasicSelectHandler"> <property name="Sql">
"SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno FROM emp"</property> <property name="DataReaderHandler"> <component class="Seasar.Extension.ADO.Impl.DictionaryListDataReaderHandler"/> </property> </component> </components>

Seasar.Examples.Reference.ADO.SelectDictionaryListClient

C#
using System;
using System.Collections;
using Seasar.Extension.ADO;
using Seasar.Framework.Container;
using Seasar.Framework.Container.Factory;

namespace Seasar.Examples.Reference.ADO
{
    public class SelectDictionaryListClient
    {
        private const string PATH = "Seasar.Examples/Reference/ADO/SelectDictionaryList.dicon";

        public void Main()
        {
            IS2Container container = S2ContainerFactory.Create(PATH);
            container.Init();
            try
            {
                ISelectHandler handler = 
                    SelectHandler) container.GetComponent("SelectDictionaryListHandler");
                IList result = (IList) handler.Execute(null);
                for (int i = 0; i < result.Count; ++i)
                {
                    Console.Out.WriteLine(DictionaryUtil.ToDecorateString((IDictionary) result[i]));
                }
            }
            finally
            {
                container.Destroy();
            }
        }
    }
}

実行結果

DEBUG 2006-06-19 23:43:24,749 [9] 論理的なコネクションを取得しました
DEBUG 2006-06-19 23:43:24,765 [9] 論理的なコネクションを閉じました
ename=SMITH, hiredate=1980/12/17 0:00:00, comm=null, deptno=20, job=CLERK, empno=7369,
 sal=800.00, mgr=7902
ename=ALLEN, hiredate=1981/02/20 0:00:00, comm=300.00, deptno=30, job=SALESMAN, empno=7499,
 sal=1600.00, mgr=7698
ename=WARD, hiredate=1981/02/22 0:00:00, comm=500.00, deptno=30, job=SALESMAN, empno=7521,
 sal=1250.00, mgr=7698
ename=JONES, hiredate=1981/04/02 0:00:00, comm=null, deptno=20, job=MANAGER, empno=7566,
 sal=2975.00, mgr=7839
ename=MARTIN, hiredate=1981/09/28 0:00:00, comm=1400.00, deptno=30, job=SALESMAN, empno=7654,
 sal=1250.00, mgr=7698
ename=BLAKE, hiredate=1981/05/01 0:00:00, comm=null, deptno=30, job=MANAGER, empno=7698,
 sal=2850.00, mgr=7839
ename=CLARK, hiredate=1981/06/09 0:00:00, comm=null, deptno=10, job=MANAGER, empno=7782,
 sal=2450.00, mgr=7839
ename=SCOTT, hiredate=1982/12/09 0:00:00, comm=null, deptno=20, job=ANALYST, empno=7788,
 sal=3000.00, mgr=7566
ename=KING, hiredate=1981/11/17 0:00:00, comm=null, deptno=10, job=PRESIDENT, empno=7839,
 sal=5000.00, mgr=null
ename=TURNER, hiredate=1981/09/08 0:00:00, comm=0.00, deptno=30, job=SALESMAN, empno=7844,
 sal=1500.00, mgr=7698
ename=ADAMS, hiredate=1983/01/12 0:00:00, comm=null, deptno=20, job=CLERK, empno=7876,
 sal=1100.00, mgr=7788
ename=JAMES, hiredate=1981/12/03 0:00:00, comm=null, deptno=30, job=CLERK, empno=7900,
 sal=950.00, mgr=7698
ename=FORD, hiredate=1981/12/03 0:00:00, comm=null, deptno=20, job=ANALYST, empno=7902,
 sal=3000.00, mgr=7566
ename=MILLER, hiredate=1982/01/23 0:00:00, comm=null, deptno=10, job=CLERK, empno=7934,
 sal=1300.00, mgr=7782

検索処理(Dictionary)

1件のDictionaryを取得することもできます。DataReaderHandlerにはDictionaryDataReaderHandlerを使います。

Seasar.Examples.Reference.ADO.SelectDictionary.dicon

<components>
  <include path="Seasar.Examples/Ado.dicon" />
  <component name="SelectDictionaryClient" class="Seasar.Examples.Reference.ADO.SelectDictionaryClient"/>
  <component name="SelectDictionaryHandler" class="Seasar.Extension.ADO.Impl.BasicSelectHandler">
    <property name="Sql">
"SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno
FROM emp WHERE empno = @empno"</property> <property name="DataReaderHandler"> <component class="Seasar.Extension.ADO.Impl.DictionaryDataReaderHandler"/> </property> </component> </components>

Seasar.Examples.Reference.ADO.SelectDictionaryClient

C#
using System;
using System.Collections;
using Seasar.Extension.ADO;
using Seasar.Framework.Container;
using Seasar.Framework.Container.Factory;

namespace Seasar.Examples.Reference.ADO
{
    public class SelectDictionaryClient
    {
        private const string PATH = "Seasar.Examples/Reference/ADO/SelectDictionary.dicon";

        public void Main()
        {
            IS2Container container = S2ContainerFactory.Create(PATH);
            container.Init();
            try
            {
                ISelectHandler handler =
                    (ISelectHandler) container.GetComponent("SelectDictionaryHandler");
                IDictionary result = (IDictionary) handler.Execute(new object[] { 7788 });
                Console.Out.WriteLine(DictionaryUtil.ToDecorateString(result));
            }
            finally
            {
                container.Destroy();
            }
        }
    }
}

実行結果

DEBUG 2006-06-19 23:46:25,640 [9] 論理的なコネクションを取得しました
DEBUG 2006-06-19 23:46:25,656 [9] 論理的なコネクションを閉じました
ename=SCOTT, hiredate=1982/12/09 0:00:00, comm=null, deptno=20, job=ANALYST, empno=7788,
 sal=3000.00, mgr=7566

更新処理

更新するためにはBasicUpdateHandlerを使います。次のようなプロパティが用意されています。

Seasar.Extension.ADO.Impl.BasicUpdateHandler

プロパティ 説明 S2Containerでの設定例
DataSource DataSource 通常自動的に設定されます。
Sql 実行したいSQL文 "UPDATE emp SET ename = @ename WHERE empno = @empno "

Seasar.Examples.Reference.ADO.Update.dicon

<components>
  <include path="Seasar.Examples/Ado.dicon" />
  <component name="UpdateClient" class="Seasar.Examples.Reference.ADO.UpdateClient"/>
  <component name="UpdateHandler" class="Seasar.Extension.ADO.Impl.BasicUpdateHandler">
    <property name="Sql">"UPDATE emp SET ename = @ename WHERE empno = @empno"</property>
  </component>
</components>

Seasar.Examples.Reference.ADO.UpdateClient

C#
using System;
using Seasar.Extension.ADO;
using Seasar.Framework.Container;
using Seasar.Framework.Container.Factory;

namespace Seasar.Examples.Reference.ADO
{
    public class UpdateClient
    {
        private const string PATH = "Seasar.Examples/Reference/ADO/Update.dicon";

        public void Main()
        {
            IS2Container container = S2ContainerFactory.Create(PATH);
            container.Init();
            try
            {
                IUpdateHandler handler = (IUpdateHandler) container.GetComponent("UpdateHandler");
                int result = (int) handler.Execute(new object[] { "SCOTT", 7788 });
                Console.Out.WriteLine(result);
            }
            finally
            {
                container.Destroy();
            }
        }
    }
}

実行結果

DEBUG 2006-06-19 23:55:46,999 [9] 論理的なコネクションを取得しました
DEBUG 2006-06-19 23:55:47,031 [9] 論理的なコネクションを閉じました
1

NULL値の扱いについて

NET Framework型とデータベースの列を対応させる場合、列にNULL値が格納されていると例外が発生する場合があります。 .NET Framework型がSystem.Int32等の構造体の場合、NULLを表現できないからです。

列にNULL値が格納される場合、

の方法を使用します。データベースのデータ型と各方法の対応を次の表に示します。

System.Data.DbType.NET Framework型NullablesSystem.Data.SqlTypesSystem.Nullable
BooleanBooleanNullableBooleanSqlBooleanNullable<Boolean>
ByteByteNullableByteSqlByteNullable<Byte>
BinaryByte[]NullableByteSqlBinaryNullable<Byte>
DateTimeDateTimeNullableDateTimeSqlDateTimeNullable<DateTime>
DecimalDecimalNullableDecimalSqlDecimalNullable<Decimal>
DoubleDoubleNullableDoubleSqlDoubleNullable<Double>
SingleSingleNullableSingleSqlSingleNullable<Single>
GuidGuidNullableGuidSqlGuidNullable<Guid>
Int16Int16NullableInt16SqlInt16Nullable<Int16>
Int32Int32NullableInt32SqlInt32Nullable<Int32>
Int64Int64NullableInt64SqlInt64Nullable<Int64>
StringString-SqlString-
TimeTimeSpan--Nullable<TimeSpan>
SByteSByteNullableSByte-Nullable<SByte>

NHibernateContribのNullables

NHibernateContribのNullablesを利用する場合、以下のファイル(アセンブリ)への参照を追加する必要があります。

  • s2container.net/lib/Nullables.dll

ソースファイルからは、次のように使用します。

  • Nullables名前空間をインポートする必要があります。
  • NULLであるか確認する場合、HasValueプロパティを使用します。
  • 値を取り出す場合、Valueプロパティを使用します。

C#
using System.Text;
using Nullables;

namespace Foo
{
    public class Bar
    {
        private NullableInt64 id;

        public NullableInt64 Id
        {
            get { return id; }
            set { id = value; }
        }

        private NullableBoolean boolType;

        public NullableBoolean BoolType
        {
            get { return boolType; }
            set { boolType = value; }
        }

        public override string ToString()
        {
            StringBuilder buf = new StringBuilder();
            buf.Append(id.HasValue ? id.Value.ToString() : "NULL").Append(", ");
            buf.Append(boolType.HasValue ? boolType.Value.ToString() : "NULL").Append(", ");
            return buf.ToString();
        }
    }
}

System.Data.SqlTypesのNull

ソースファイルからは、次のように使用します。

  • System.Data.SqlTypes名前空間をインポートする必要があります。
  • NULLであるか確認する場合、IsNullプロパティを使用します。
  • 値を取り出す場合、Valueプロパティを使用します。

C#
using System.Data.SqlTypes;
using System.Text;

namespace Foo
{
    public class Bar
    {
        private SqlInt64 id;

        public SqlInt64 Id
        {
            get { return id; }
            set { id = value; }
        }

        private SqlBoolean boolType;

        public SqlBoolean BoolType
        {
            get { return boolType; }
            set { boolType = value; }
        }

        public override string ToString()
        {
            StringBuilder buf = new StringBuilder();
            buf.Append(!id.IsNull ? id.Value.ToString() : "NULL").Append(", ");
            buf.Append(!boolType.IsNull ? boolType.Value.ToString() : "NULL").Append(", ");
            return buf.ToString();
        }
    }
}

System.Nullable(.NET 2.0以降)

.NET Framework 2.0以降を使用している場合、Nullable型を使用することが可能です。

ソースファイルからは、次のように使用します。

  • System名前空間をインポートする必要があります。
  • NULLであるか確認する場合、HasValueプロパティを使用します。
  • 値を取り出す場合、Valueプロパティを使用します。

C#
using System;
using System.Text;

namespace Foo
{
    public class Bar
    {
        private Nullable<Int64> id;

        public Nullable<Int64> Id
        {
            get { return id; }
            set { id = value; }
        }

        private Nullable<Boolean> boolType;

        public Nullable<Boolean> BoolType
        {
            get { return boolType; }
            set { boolType = value; }
        }

        public override string ToString()
        {
            StringBuilder buf = new StringBuilder();
            buf.Append(id.HasValue ? id.Value.ToString() : "NULL").Append(", ");
            buf.Append(boolType.HasValue ? boolType.Value.ToString() : "NULL").Append(", ");
            return buf.ToString();
        }
    }
}

パラメータマーカー(@, :, ?)の扱い

SQL文に埋め込むパラメータマーカーは、ADO.NETのデータプロパイダによって異なります。 (SqlClientは"@parmname"、OracleClientは":parmname"、OleDbは、"?"、Odbcは、"?")

S2ADOではデータプロパイダごとにパラメータマーカーを自動的に切り替えるため、データプロパイダに依存しないSQL文の作成を可能にしています。

例えば、次のようになります。

データプロバイダ SQL文
(ユーザが記述したSQL文) SELECT * FROM emp WHERE empno = @empno OR empno = :empno OR empno = ?
SqlClient SELECT * FROM emp WHERE empno = @0 OR empno = @1 OR empno = @2
OracleClient SELECT * FROM emp WHERE empno = :0 OR empno = :1 OR empno = :2
OleDb SELECT * FROM emp WHERE empno = ? OR empno = ? OR empno = ?
Odbc SELECT * FROM emp WHERE empno = ? OR empno = ? OR empno = ?

※SQL文に複数のパラメータマーカーを混在することは可能ですが、可読性の点から単一のパラメータマーカーを使用してください。