Seasarプロジェクト ＞ Seasar.NETプロジェクト ＞ S2Container.NET ＞ S2ADO

# 目次

上へ

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

- データ操作

- 検索処理(BeanList)
- 検索処理(Bean)
- 検索処理(DictionaryList)
- 検索処理(Dictionary)
- 更新処理

- NULL値の扱い
  - NHibernateContribのNullables(バージョン1.3.7から廃止)
  - System.Data.SqlTypesのNull
  - System.Nullable(.NET 2.0以降)
- パラメータマーカー(@, :, ?)の扱い
- OracleのUnicode問題(バージョン1.2.9以降)
- Booleanの扱い(バージョン1.2.9以降)

# データ操作

上へ

## 検索処理(BeanList)

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

### Seasar.Extension.ADO.Impl.BasicSelectHandler

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

      <arg>Seasar.Examples.Reference.
    ADO.Employee</arg>

    </component>
CommandTimeout | コマンドが実行されるまでの待機時間(秒)。値が-1の場合は特に設定しない (System.Data.IDbCommand. CommandTimeoutプロパティの規定値が適用)。 |

### 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,

## 検索処理(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 = (ISelectHandler)
                        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値が格納される場合、 以下の2つの方法を使用します。

- NHibernateContribのNullables(バージョン1.3.7から廃止)
- System.Data.SqlTypesのNull
- System.Nullable(.NET 2.0以降)

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

System.Data.DbType | .NET Framework型 | Nullables | System.Data.SqlTypes | System.Nullable
--- | --- | --- | --- | ---
Boolean | Boolean | NullableBoolean | SqlBoolean | Nullable<Boolean>
Byte | Byte | NullableByte | SqlByte | Nullable<Byte>
Binary | Byte[] | NullableByte | SqlBinary | Nullable<Byte>
DateTime | DateTime | NullableDateTime | SqlDateTime | Nullable<DateTime>
Decimal | Decimal | NullableDecimal | SqlDecimal | Nullable<Decimal>
Double | Double | NullableDouble | SqlDouble | Nullable<Double>
Single | Single | NullableSingle | SqlSingle | Nullable<Single>
Guid | Guid | NullableGuid | SqlGuid | Nullable<Guid>
Int16 | Int16 | NullableInt16 | SqlInt16 | Nullable<Int16>
Int32 | Int32 | NullableInt32 | SqlInt32 | Nullable<Int32>
Int64 | Int64 | NullableInt64 | SqlInt64 | Nullable<Int64>
String | String | - | SqlString | -
Time | TimeSpan | - | - | Nullable<TimeSpan>
SByte | SByte | NullableSByte | - | Nullable<SByte>

## NHibernateContribのNullables(バージョン1.3.7から廃止)

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以降)

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

- 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文に複数のパラメータマーカーを混在することは可能ですが､可読性の点から単一のパラメータマーカーを使用してください。

# OracleのUnicode問題(バージョン1.2.9以降)

上へ

Oracle Data Provider .NET(ODP.NET)は、Unicodeのマッピングに一部問題があり、 ～が化けてしまいます。この問題に対処するには、Ado.diconにOracleDataReaderFactoryの設定を追加します。

    <components namespace="Ado">
      ....
      <component class="Seasar.Extension.ADO.Impl.OracleDataReaderFactory" />
    </components>

# Booleanの扱い(バージョン1.2.9以降)

上へ

Oracleのようにbool型に対応していないRDBMSもあります。 この問題に対処するには、Ado.diconにBooleanToIntCommandFactoryの設定を追加します。

    <components namespace="Ado">
      ....
      <component class="Seasar.Extension.ADO.Impl.BooleanToIntCommandFactory" />
    </components>

© Copyright The Seasar Project and the others 2004-2009, all rights reserved.