いろいろ備忘録日記

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

ADO.NET入門記-005 (接続型のデータの読み取り(IDbCommand, DbCommand, ExecuteScalar, ExecuteReader))


ADO.NETには、2種類のタイプがあります。
一つは、接続型。つまり、コネクションを開いた状態でデータの読み取りなどを行なうパターン。
もう一つは、非接続型。データのやり取りを行なう時のみコネクションを開いていて、データを読み取り、
コネクションとは分離された状態でデータを編集したりするパターンです。


接続型の代表格が、DbConnection, DbCommand, DbDataReaderなどです。
非接続型の代表格が、DataSet, DataTableなどです。


DataAdapterは、接続型と非接続型との間を繋ぐブリッジみたいなものです。


今回は、接続型のデータの読み取りをしてみます。
使うのは、DbCommandのExecuteXXXXXメソッドです。
以下の3つが存在します。

  • ExecuteScalar
    • 単一の値を取得する際に利用します。
  • ExecuteReader
    • 複数の値を取得する際に利用します。
  • ExecuteNonQuery
    • 結果を返却しないクエリの場合に使用します。(Insert, Update, Delete等)


ExecuteNonQueryについては、次回に記述します。


今回、以下のテーブルが存在するとします。

create table AdoNetSample006Table(
     id   int identity primary key
    ,name varchar(50)  not null
);


そして、以下のデータが追加されているとします。

insert into AdoNetSample006Table (name) values ('gsf_zero1');
insert into AdoNetSample006Table (name) values ('gsf_zero2');
insert into AdoNetSample006Table (name) values ('gsf_zero3');
insert into AdoNetSample006Table (name) values ('gsf_zero4');
insert into AdoNetSample006Table (name) values ('gsf_zero5');
insert into AdoNetSample006Table (name) values ('gsf_zero6');


以下サンプルコードです。

using System;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Diagnostics;

using NUnit.Framework;

using Gsf.Lib.UnitTests;

namespace Gsf.Samples.AdoNet {

    [TestFixture()]
    public class AdoNetSample006 : TestBase{

        ConnectionStringSettings _settings = ConfigurationManager.ConnectionStrings["AdoNetSampleDB"];

        [Test()]
        public void ExecuteScalarの動作を確認(){
            
            using(DbConnection conn = DbProviderFactories.GetFactory(_settings.ProviderName).CreateConnection()){

                conn.ConnectionString = _settings.ConnectionString;
                conn.Open();

                //
                // コマンドの作成
                //
                DbCommand command   = conn.CreateCommand();
                command.CommandText = "select count(id) from AdoNetSample006Table";

                //
                // 実行
                //
                // 結果は、object型で返却されるので実際に利用する際にはキャストが必要になります。
                //
                Debug.WriteLine(string.Format("件数:{0}", command.ExecuteScalar()));

            }
        }

        [Test()]
        public void ExecuteReaderの動作を確認(){

            using(DbConnection conn = DbProviderFactories.GetFactory(_settings.ProviderName).CreateConnection()){

                conn.ConnectionString = _settings.ConnectionString;
                conn.Open();

                //
                // コマンドの作成
                //
                DbCommand command = conn.CreateCommand();
                command.CommandText = "select id, name from AdoNetSample006Table order by id";

                //
                // 実行
                //
                // 結果は、DbDataReader型で返却されます。
                //
                // 基本パターンとして、IDataReaderはIDisposableを継承しているので
                // usingが使用可能です。その後、DbDataReader.HasRowsプロパティにより
                // 行の有無を確認します。その後は、IDataReader.Readメソッドを使用して
                // カーソルを進めながら値を取得します。
                //
                // 値を取得するのに、よく使うメソッドは以下のものです。
                //     GetOrdinal    :指定した名前の列の序数を取得します。序数とは列の位置番号の事です。
                //     Itemプロパティ:C#の場合は、インデクサとなります。
                //     GetName       :指定した序数のカラム名を取得します。
                //
                using(DbDataReader reader = command.ExecuteReader()){

                    if(reader.HasRows){

                        int idOrdinal   = reader.GetOrdinal("id");
                        int nameOrdinal = reader.GetOrdinal("name");

                        for(; reader.Read();){

                            Debug.WriteLine(
                                string.Format(
                                     "{0}({1}): {2}, {3}({4}): {5}"
                                    ,reader.GetName(idOrdinal)
                                    ,idOrdinal
                                    ,reader[idOrdinal]
                                    ,reader.GetName(nameOrdinal)
                                    ,nameOrdinal
                                    ,reader[nameOrdinal]
                                )
                            );

                        }
                    }
                }

                //
                // DbDataReaderはforeach可能なオブジェクトです。
                // foreachすると、各行ごとのDbDataRecordオブジェクトが
                // 返されます。
                //
                // ExecuteReaderメソッドには、CommandBehavior列挙体を渡すことが出来ます。
                // 通常よく使用するのは、CommandBehavior.CloseConnectionです。
                // これを指定すると、このDataReaderの処理が終了後、関連するコネクションが閉じられます。
                //
                using(DbDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection)){

                    if(reader.HasRows){

                        int idOrdinal   = reader.GetOrdinal("id");
                        int nameOrdinal = reader.GetOrdinal("name");

                        foreach(DbDataRecord record in reader){

                            Debug.WriteLine(
                                string.Format(
                                     "{0}({1}): {2}, {3}({4}): {5}"
                                    ,record.GetName(idOrdinal)
                                    ,idOrdinal
                                    ,record[idOrdinal]
                                    ,record.GetName(nameOrdinal)
                                    ,nameOrdinal
                                    ,record[nameOrdinal]
                                )
                            );
                        }
                    }
                }
            }
        }
    }
}