DataSetとDataAdapterとかが実によくわからん。

データベースからDataSetとやらを作ってDataGridViewに一覧表示みたいな事やろうとした場合、

  1. サーバーエクスプローラでデータベースに接続
  2. プロジェクトから新規作成でDataSetを作成
  3. サーバーエクスプローラのテーブル(ビュー)をDataSetのエディタにD&D
  4. データソースから今作ったDatasetのテーブルをFormにドロップ

なんてので出来ちゃうので大変に便利なんだが、BindingSourceだとかDataAdapterやらが勝手に作成されるのが気持ち悪いので調べてみる。

分かってることと分からんことの整理

java.sqlっぽいので基本的なSQL実行まわりってのは理解が簡単。

java C#
java.sql.Connection System.Data.Sql.SqlConnection
java.sql.Statement System.Data.Sql.SqlCommand
java.sql.ResultSet System.Data.Sql.SqlDataReader

C#での接続から表の取り出しってのはこんなの

  SqlConnection connection = new SqlConnection(strConnectionString);
  SqlCommand command = connection.createCommand();
  command.CommandText = "select * from hoge where hoge_name=@hogeName";
  command.Parameters.Add("@hogeName",DbType.Varchar,255).Value="hoge";
  SqlDataReader reader = command.ExecuteReader();
  while (reader.Read()){
    Console.Writeln(Convert.ToString(reader["hoge"]));
  }

Readerから取り出されるのが連想配列的なのと取り出してからキャストするのが違うぐらいでほとんどJavaと一緒。

逆に分からん事はこれ以外のDataBindingSource/DataAdapter/DataSetあたり。
ほとんどじゃん。ひー。

少しづつ棚卸し

MSのサンプルから眺めてみる。

http://support.microsoft.com/kb/307587/ja

string sConnectionString;

// Modify the following string to correctly connect to your SQL Server.
sConnectionString = "Password=<strong password>;User ID=<username>;"
	+ "Initial Catalog=pubs;"
	+ "Data Source=(local)";

SqlConnection objConn = new SqlConnection(sConnectionString);
objConn.Open();

// Create an instance of a DataAdapter.
SqlDataAdapter daAuthors = new SqlDataAdapter("Select * From Authors", objConn);

// Create an instance of a DataSet, and retrieve data from the Authors table.
DataSet dsPubs = new DataSet("Pubs");
daAuthors.FillSchema(dsPubs,SchemaType.Source, "Authors");
daAuthors.Fill(dsPubs,"Authors");

SqlDataAdapter.FillSchemaとか何だろ

MSDNを引いてみる。

SqlDataAdapter は、DataSet と SQL Server の間でデータを取得および保存するための、ブリッジの役割を果たします。SqlDataAdapter は、このブリッジを提供するために、データ ソースに対して適切な Transact-SQL ステートメントを使用して、DataSet 内のデータをデータ ソース内のデータと一致するように変更する Fill と、データ ソース内のデータを DataSet 内のデータと一致するように変更する Update で、割り当てを行います。

SqlDataAdapter は、DataSet にデータを読み込むときに、返されたデータを格納するテーブルおよび列が存在しない場合は、それらを作成します。ただし、MissingSchemaAction プロパティを AddWithKey に設定しない限り、暗黙的に作成されたスキーマには主キー情報は設定されません。DataSet にデータを格納する前に、FillSchema を使用して、主キー情報を含むスキーマを SqlDataAdapter に作成させることもできます。詳細については、「DataSet への既存の制約の追加」を参照してください。

指定した DataSet に DataTable を追加し、指定した SchemaType および DataTable に基づいて、データ ソース内のスキーマと一致するようにスキーマを設定します。
(略)
解説

このメソッドは、SelectCommand を使用して、データ ソースからスキーマ情報を取得します。
また、FillSchema は、次の規則に従って、PrimaryKey プロパティと Constraints プロパティも設定します。

* SelectCommand によって 1 つ以上の主キー列が返された場合は、それを DataTable の主キー列として使用します。
* 主キー列が返されず、一意の列が返された場合、それらの列すべてが null 値を許容しないときに限り、一意の列を主キーとして使用します。いずれかの列が null 値を許容するときは、ConstraintCollection に UniqueConstraint を追加します。PrimaryKey プロパティは設定しません。
* 主キー列と一意の列の両方が返された場合は、主キー列を DataTable の主キー列として使用します。

DataAdapter自体はテーブル*1とDataset内のDataTableとやらとの間を取り持つオブジェクトなのかなぁ。

DataTableはDatasetから引く

解説

データ ソースから取得されたデータのメモリ内キャッシュである DataSet は、ADO.NET アーキテクチャの主要コンポーネントです。DataSet は、DataRelation オブジェクトと相互に関連付けることができる DataTable オブジェクトのコレクションで構成されます。UniqueConstraint オブジェクトと ForeignKeyConstraint オブジェクトを使用して、DataSet 内でデータの整合性を適用することもできます。DataSet オブジェクトの使用の詳細については、「ADO.NET での DataSet の使用」を参照してください。

DataTable オブジェクトにはデータを格納できるのに対して、DataRelationCollection を使用するとテーブルの階層構造内を移動できます。テーブルは、Tables プロパティを使用してアクセスできる DataTableCollection に格納されます。DataTable オブジェクトにアクセスするときは、条件付きで大文字と小文字が区別されることに注意してください。たとえば、"mydatatable" という名前の DataTable と "Mydatatable" という名前のテーブルがある場合は、この 2 つのーブルのどちらかを検索する文字列は大文字と小文字を区別すると見なされます。ただし、"mydatatable" という名前は存在するが "Mydatatable" という名前が存在しない場合は、検索文字列は大文字と小文字を区別しないと見なされます。DataTable オブジェクトの使用の詳細については、「DataTable の作成」を参照してください。

DataSet では、データとスキーマXML ドキュメントとして読み取ったり、書き込んだりできます。読み込んだデータとスキーマは、HTTP で転送でき、XML 対応のすべてのプラットフォームおよびアプリケーションで使用できます。スキーマXML スキーマとして保存するには WriteXmlSchema メソッドを使用します。スキーマとデータの両方を保存するには WriteXml メソッドを使用します。スキーマとデータの両方を含む XML ドキュメントを読み取るには、ReadXml メソッドを使用します。

ああ。なんとなくクリアに。
DataSet自体が表のキャッシュコレクションになってて、その最小単位のキャッシュがDataTableか。

こんな感じ?

手書きで関連を起こしてみた。UMLもどき記法は俺ジナル。

  • AdapterはSQLで表現される結果セット*2と、ローカルデータキャッシュのDataTable*3との媒介になるオブジェクトで、fill()とかupdate()を使って相互のデータを同期させる役割を持ってる。
  • DataSet.DataTableはAdapter.FillSchema()で結果セットと同じ制約や型を持ったテーブルとして自動定義される。
  • DataSetはXMLSchemaとして定義できる。VisualStudioでプロジェクトから新規作成で作るDatasetってのは要するにコレ。
  • DataGridViewなんかは定義済みのDataSetからスキーマを読み取ることで表を自動作成してる。

うーん。良くできてるな。

*1:というかSQLの結果セット

*2:テーブルも含む

*3:Dataset.DataTable