いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

ADO.NET入門記-008 (DataAdapterの使用(Select) (DbDataAdapter, Fill, SelectCommand))


DataAdapterクラスは、ADO.NETにおいて接続型オブジェクト(DataReader等)と非接続型オブジェクト(DataSet, DataTable)
の橋渡しを行なう為のクラスです。


このクラスを利用すると、クエリの結果をデータテーブル及びデータセットに簡単に取り込めるようになります。


DataAdapterは、各データプロバイダ毎に実装が行なわれていますが、全て以下の基本クラスを継承して作成されています。

System.Data.Common.DbDataAdapter


また、通常データアダプタは以下のコンストラクタから作成します。

// デフォルトコンストラクタ.
DbDataAdapter adapter = new SqlDataAdapter();
DbDataAdapter adapter = new SqlDataAdapter("select用のSQL", "接続文字列");
DbDataAdapter adapter = new SqlDataAdapter(Select用のCommandオブジェクト);


クエリ結果を、非接続型オブジェクトに取り込むには以下のメソッドを使用します。

adapter.Fill(データセット);
adapter.Fill(データセット, "内部データテーブルに付けるテーブル名");
adapter.Fill(データテーブル);


非接続型オブジェクトの状態をデータベースに反映するには以下のメソッドを使用します。

adapter.Update(データセット, "更新対象のデータセット内部のテーブル名");
adapter.Update(データテーブル);

Updateメソッドについては、次回記述します。


また、データアダプタはコネクションの扱いについて以下の特徴をもっています。

  • 利用するコネクションが既にOpenされている場合、処理終了後もそのコネクションを閉じない。
  • 利用するコネクションがまだOpenされていない場合、そのコネクションを開き、処理終了後そのコネクションを閉じる。


つまり、処理終了後に必ず処理を開始する前の状態に戻すという事になります。
複数のアダプタ間で同じコネクションを利用したい場合は、予めコネクションを開いた状態でアダプターに渡します。

DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.SqlClient");
using(DbConnection conn = factory.CreateConnection()){
    conn.ConnectionString = "xxxxx";
    conn.Open();

    using(DbDataAdapter adapter = new SqlDataAdapter("select xx from xx", conn)){
    }

    using(DbDataAdapter adapter = new SqlDataAdapter("select xxx from xxx", conn)){
    }
}


以下、サンプルです。
今回、以下のテーブルが存在し、予め以下のデータが挿入されているとします。

create table AdoNetSampleDB(
     id int primary key
    ,name varchar(50)
    ,age int
);

insert into AdoNetSampleDB (id, name, age) values (1, 'gsf_zero1', 27);
insert into AdoNetSampleDB (id, name, age) values (2, 'gsf_zero2', 28);
insert into AdoNetSampleDB (id, name, age) values (3, 'gsf_zero3', 29);
insert into AdoNetSampleDB (id, name, age) values (4, 'gsf_zero4', 30);
insert into AdoNetSampleDB (id, name, age) values (5, 'gsf_zero5', 31);
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;

using NUnit.Framework;

using Gsf.Lib.UnitTests;


namespace Gsf.Samples.AdoNet {

    [TestFixture()]
    public class AdoNetSample009 : TestBase{

        [Test()]
        public void DataAdapterを使用してデータの取得を行なってみる(){
            //
            // DataAdapterを利用すると、発行したクエリの結果を非接続型オブジェクトに
            // 取り込む事が出来ます。非接続型オブジェクトとは、DataSetやDataTableの事です。
            //
            // つまり、DataAdapterは接続型と非接続型の橋渡しをするためのオブジェクトとなります。
            //
            // DataAdapterオブジェクトは、動作するためにデータを取得するためのDbCommandオブジェクトを
            // 必要とします。必要なコマンドオブジェクトを指定して、初めてFillメソッドが呼べるようになります。
            //
            // また、DataAdapterは利用するコネクションオブジェクトについて以下の動作を行ないます。
            // ・利用するコネクションが既にOpen状態の場合、そのコネクションを使用し処理終了後も閉じない。
            // ・利用するコネクションがまだOpenされていない場合、そのコネクションを内部でOpenし処理終了後閉じる。
            //
            DbProviderFactory factory = DbProviderFactories.GetFactory(_settings.ProviderName);
            using(DbConnection conn = factory.CreateConnection()){
                
                conn.ConnectionString = _settings.ConnectionString;
                conn.Open();

                //
                // データ取得に使用するコマンドを作成.
                //
                DbCommand selectCommand   = conn.CreateCommand();
                selectCommand.CommandText = "select id, name, age from AdoNetSampleTable009 order by id";

                //
                // DataAdapterを生成する.
                //
                using(DbDataAdapter adapter = factory.CreateDataAdapter()){
                    //
                    // アダプターに取得コマンドを設定.
                    // (SelectCommand)
                    //
                    adapter.SelectCommand = selectCommand;

                    //
                    // 結果を、非接続型オブジェクトであるデータセットに取り込む.
                    //
                    // Fillメソッドの第二引数は、取り込み先のデータセット内にどのような名前で
                    // テーブルを作成するのかを指示しています。この場合だとこのデータセット内に
                    // "AdoNetSampleTable009"というNameのデータテーブルが作成されます。
                    //
                    DataSet ds = new DataSet();
                    Assert.AreEqual(5, adapter.Fill(ds, "AdoNetSampleTable009"));

                    //
                    // 取得した結果を確認
                    //
                    foreach(DataRow row in ds.Tables["AdoNetSampleTable009"].Rows){
                        Console.WriteLine(string.Format("id:{0}, name:{1}, age:{2}", row["id"], row["name"], row["age"]));
                    }
                }   
            }
        }

        [Test()]
        public void DataAdapter自身にコネクションのオープンとクローズを任せる(){

            string sql = "select id, name, age from AdoNetSampleTable009";

            //
            // DataAdapterには、Select用のSQLと接続文字列を渡せるバージョンのコンストラクタがあります。
            // この場合、コネクションのオープンはDataAdapter自身が行ないます。
            // このほかにも、コンストラクタにCommandオブジェクトを指定できるバージョンもあります。
            //
            using(DbDataAdapter adapter = new System.Data.SqlClient.SqlDataAdapter(sql, _settings.ConnectionString)){
                //
                // 今度は、Fillの引数にデータテーブルを渡し、結果を取り込んでみる。
                //
                DataTable dt = new DataTable();
                Assert.AreEqual(5, adapter.Fill(dt));

                //
                // 取得した結果を確認
                //
                foreach(DataRow row in dt.Rows){
                    Console.WriteLine(string.Format("id:{0}, name:{1}, age:{2}", row["id"], row["name"], row["age"]));
                }
            }
        }
    }
}