エンタープライズ.net dataset
DESCRIPTION
DataSetプログラミング入門TRANSCRIPT
http://biki.jp.net/enterprisenet
DataSet プログラミング入門
http://biki.jp.net/enterprisenet
内容
目的 ADO.NETの主要機能であるDataSetの基本的なプログラミング手法を理解する
アジェンダ ADO.NETの概要
DataSetの概要
型付DataSetの定義
データベースからデータの読込
DataSetデータのアクセス
DataSetデータの編集
DataSetの利用
DataSet応用&Tips
http://biki.jp.net/enterprisenet
ADO.NETの概要
http://biki.jp.net/enterprisenet
ADO.NETの概要
ADO.NET の主要コンポーネント DataSet .NET データプロバイダ
DataSet ADO.NET の非接続型アーキテクチャの中心となるコンポーネント データの行と列で構成される複数の DataTableのコレクションから構成 DataTableオブジェクトはデータに関する主キー、外部キー、制約および、リレーションシップ情報から構成されている
.NET データプロバイダ Connectionオブジェクトはデータソースとの接続機能を提供 Commandオブジェクトによってデータベースコマンドにアクセス DataReaderはデータソースからの高いパフォーマンスの読み取り機能 DataAdapterは DataSetオブジェクトとデータベースの間のブリッジを提供
DataSetの概要
DataSet
DataRow(行)
DataTable
DataColumn(列)
DataTable
(テーブル)
DataTable
DataRelation
Constraint(制約)
(リレーション)
DataView
http://biki.jp.net/enterprisenet
DataSetの概要
DataTable メモリ常駐データを含む単一テーブルを表現 DataColumn、DataRow、Constraintのコレクションを保持
DataColumn テーブルの列のスキーマ情報 列名、データ型
DataRow テーブルの行データ 現在の変更状態や現在・変更前の複数バージョンのデータを保持
Constraint 列に適用する制約 主キー制約、一意キー制約
DataRelation 2 つの DataTable オブジェクト間の親子のリレーションシップ リレーションシップを利用するとDataSet内部のテーブル間を移動できる
DataView 並べ替え、フィルタ処理などカスタマイズされた DataTable のビューを提供
http://biki.jp.net/enterprisenet
型付DataSetの定義
定義するサンプルDataSet
pub_id pub_name ….
SampleDataset
publishers テーブル(親)
Title_id title … Pub_id … comment
titles テーブル(子)
http://biki.jp.net/enterprisenet
データセットの作成
① プロジェクト-新しい項目の追加②データセットを選択
http://biki.jp.net/enterprisenet
型付DataSetのテーブル定義
大きくは以下の2つの方法を利用 ツールボックスを利用してマニュアルで作成
既存のデータベースのテーブルを利用して作成
サーバーエクスプローラのテーブルをDrag&Drop
http://biki.jp.net/enterprisenet
型付DataSetのテーブル定義
複数のテーブルを配置することが可能
TableAdapterは今回不要なので削除しています
追加のテーブルをDrag&Drop
http://biki.jp.net/enterprisenet
型付DataSetのリレーション定義
リレーションの作成 複数配置したテーブル間に関係を設定
①子テーブルを右クリックし「追加」-「リレーション」で作成②ウイザードを利用して関連するカラムを設定
http://biki.jp.net/enterprisenet
データベースからデータの読込
http://biki.jp.net/enterprisenet
データベースからデータの読込①
テーブルの読み出し
….pub_namepub_id ….pub_namepub_id
SampleDataset
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)
型付DataSet
DataSet
データベース DataAdapter.Fill
① DataSetのテーブル名を指定
②型付DataSetのテーブルを指定
http://biki.jp.net/enterprisenet
テーブルの読み出し
① DataSetのテーブル名を指定
②型付DataSetのテーブルを指定
データベースからデータの読込①
Dim ds As New DataSet()Dim adapter As New OleDbDataAdapter( _
"SELECT * FROM publishers", connectionString)adapter.Fill(ds, "publishers")
Dim ds As New SampleDataset()Dim adapter As New OleDbDataAdapter( _
"SELECT * FROM publishers", connectionString)adapter.Fill(ds.publishers)
http://biki.jp.net/enterprisenet
テーブルの読み出し
① DataSetのテーブル名を指定
②型付DataSetのテーブルを指定
データベースからデータの読込①
DataSet ds = new DataSet();OleDbDataAdapter adapter = new OleDbDataAdapter(
"SELECT * FROM publishers", connectionString);adapter.Fill(ds, "publishers");
SampleDataset ds = new SampleDataset();OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM publishers", connectionString);adapter.Fill(ds.publishers);
http://biki.jp.net/enterprisenet
データベースからデータの読込②
複数テーブルの読み出し
….pub_namepub_id ….pub_namepub_id
SampleDataset
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)データベース DataAdapter.Fill
http://biki.jp.net/enterprisenet
データベースからデータの読込②
複数テーブルの読み出し
Dim ds As New SampleDataset()Dim adapterPublishers As New OleDbDataAdapter( _
"SELECT * FROM publishers", connectionString)adapterPublishers.Fill(ds.publishers)
Dim adapterTitles As New OleDbDataAdapter( _"SELECT * FROM titles", connectionString)
adapterTitles.Fill(ds.titles)
http://biki.jp.net/enterprisenet
データベースからデータの読込②
複数テーブルの読み出し
SampleDataset ds = new SampleDataset();OleDbDataAdapter adapterPublishers = new OleDbDataAdapter(
"SELECT * FROM publishers", connectionString);adapterPublishers.Fill(ds.publishers);
OleDbDataAdapter adapterTitles = new OleDbDataAdapter("SELECT * FROM titles", connectionString);
adapterTitles.Fill(ds.titles);
http://biki.jp.net/enterprisenet
データベースからデータの読込③
データベースの複数テーブルをJoinした結果の読み出し
データベース DataAdapter.Fill
….pub_namepub_id ….pub_namepub_id
SampleDataset
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)
http://biki.jp.net/enterprisenet
データベースからデータの読込③
データベースの複数テーブルをJoinした結果の読み出し
Dim adapterTitles As New OleDbDataAdapter( _"SELECT titles.*, publishers.pub_name AS comment FROM
titles INNER JOIN publishers ON titles.pub_id = publishers.pub_id", connectionString)
adapterTitles.Fill(ds.titles)
http://biki.jp.net/enterprisenet
データベースからデータの読込③
データベースの複数テーブルをJoinした結果の読み出し
OleDbDataAdapter adapterTitles = new OleDbDataAdapter(“SELECT titles.*, publishers.pub_name AS comment FROM titles INNER JOIN publishers ON titles.pub_id =publishers.pub_id", connectionString);
adapterTitles.Fill(ds.titles);
http://biki.jp.net/enterprisenet
データベースからデータの読込④ DataSet内の他のテーブルデータの利用
pub_id pub_name ….
1 AAAA
2 BBBB
Title_id title … Pub_id … comment
1 AAAA
1 AAAA
2 BBBB
titles テーブル(子)
Titlesのcomment列に親テーブルであるpublishersの関連する行の値が自動的に設定される
Expression = "Parent.pub_name"
publishers テーブル(親)
http://biki.jp.net/enterprisenet
データベースからデータの読込④
Dim ds As New SampleDataset()ds.titles.commentColumn.Expression = "Parent.pub_name"
Dim adapterPublishers As New OleDbDataAdapter( _"SELECT * FROM publishers", connectionString)
adapterPublishers.Fill(ds.publishers)
Dim adapterTitles As New OleDbDataAdapter( _"SELECT * FROM titles", connectionString)
adapterTitles.Fill(ds.titles)
DataSet内の他のテーブルデータの利用
ヘッダー/明細型のDataSetで明細行にヘッダーカラムを表示したい場合などにも利用
http://biki.jp.net/enterprisenet
データベースからデータの読込④
SampleDataset ds = new SampleDataset();ds.titles.commentColumn.Expression = "Parent.pub_name";
OleDbDataAdapter adapterPublishers = new OleDbDataAdapter("SELECT * FROM publishers", connectionString);
adapterPublishers.Fill(ds.publishers);
OleDbDataAdapter adapterTitles = new OleDbDataAdapter("SELECT * FROM titles", connectionString);
adapterTitles.Fill(ds.titles);
DataSet内の他のテーブルデータの利用
ヘッダー/明細型のDataSetで明細行にヘッダーカラムを表示したい場合などにも利用
http://biki.jp.net/enterprisenet
DataColumn.Expressionによる計算列
UnitPrice * 0.086 UnitPrice列 * 0.086 の計算結果
Count(OrderID)列の総数
UnitPrice * Quantity UnitPrice列 * Quantity列 の計算結果
Parent.Price親テーブルの関連する行のPrice列の値
Avg(Child(Orders2Details).Price) Orders2Details リレーションで関連する子テーブルのPriceの平均
Sum(Price) Priceの合計
Convert(total, ‘System.Int32’) 型変換
Len(ItemName) 文字列長
IsNull(price, -1) Nullチェック
IIF(total>1000, ‘expensive’, ‘dear’)条件式
SUBSTRING(phone, 7, 8)文字列の取り出し
http://biki.jp.net/enterprisenet
DataSetデータのアクセス
http://biki.jp.net/enterprisenet
テーブル( DataTable )へのアクセス
DataSetのTablesプロパティを利用してアクセス
型付DataSetではTable名で直接アクセス可
型付DataSetではTableごとにDataTableの派生クラスが提供される
….pub_namepub_id ….pub_namepub_id
SampleDataset
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)
SampleDataset.titlesDataTable クラス
SampleDataset.publishersDataTable クラス
http://biki.jp.net/enterprisenet
テーブル( DataTable )へのアクセス
'テーブル数の取得tablesCount = ds.Tables.Count'テーブルオブジェクトの宣言Dim table As DataTable'1番目のテーブルを取得table = ds.Tables(0)'テーブル名がpublishersのテーブルを取得table = ds.Tables("publishers")
'テーブル数の取得tablesCount = typedDs.Tables.Count'型付テーブルオブジェクトの宣言Dim typedTable As SampleDataset.publishersDataTable'publishersテーブルを取得typedTable = typedDs.publishers
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
テーブル( DataTable )へのアクセス
//テーブル数の取得tablesCount = ds.Tables.Count;//テーブルオブジェクトの宣言DataTable table;//1番目のテーブルを取得table = ds.Tables[0];//テーブル名がpublishersのテーブルを取得table = ds.Tables["publishers"];
//テーブル数の取得tablesCount = typedDs.Tables.Count;//型付テーブルオブジェクトの宣言SampleDataset.publishersDataTable typedTable;//publishersテーブルを取得typedTable = typedDs.publishers;
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
列(DataColumn)へのアクセス
DataTableのColumnsプロパティを利用してアクセス
型付DataSetではカラム名付与されたプロパティで直接アクセス可
….pub_namepub_id ….pub_namepub_id
SampleDataset
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)typedTable.pub_nameColumn プロパティ
http://biki.jp.net/enterprisenet
列(DataColumn)へのアクセス
'列数の取得columnsCount = table.Columns.Count'列オブジェクトの宣言Dim column As DataColumn'テーブルの2列目の定義情報を取得column = table.Columns(1)'テーブルのpub_name列目の定義情報を取得column = table.Columns("pub_name")
'列数の取得columnsCount = typedTable.Columns.Count'テーブルのpub_name列目の定義情報を取得column = typedTable.pub_nameColumn
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
列(DataColumn)へのアクセス
//列数の取得columnsCount = table.Columns.Count;//列オブジェクトの宣言DataColumn column;//テーブルの2列目の定義情報を取得column = table.Columns[1];//テーブルのpub_name列の定義情報を取得column = table.Columns["pub_name"];
//列数の取得columnsCount = typedTable.Columns.Count;//テーブルのpub_name列目の定義情報を取得column = typedTable.pub_nameColumn;
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
行(DataRow)・データへのアクセス
DataTableのRowsプロパティを利用してアクセス
型付DataSetではTableごとにDataRowの派生クラスが提供される
….pub_namepub_id ….pub_namepub_id
SampleDataset
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)SampleDataset.publishersRow クラス
SampleDataset.titlesRow クラス
http://biki.jp.net/enterprisenet
行(DataRow)・データへのアクセス
'行数の取得(0の場合は行がない)rowsCount = table.Rows.Count'行オブジェクトの宣言Dim row As DataRow'テーブルの1行目を取得row = table.Rows(0)'pub_name列の値を取得pub_name = DirectCast(row("pub_name"), String)'テーブルから直接1行目の2番目の列(pub_name)の値を取得pub_name = DirectCast(table.Rows(0)(1), String)'テーブルから直接1行目のpub_nameの列の値を取得pub_name = DirectCast(table.Rows(0)("pub_name"), String)
DataSet
http://biki.jp.net/enterprisenet
行(DataRow)・データへのアクセス
'行数の取得(0の場合は行がない)rowsCount = typedTable.Rows.Count'型付行オブジェクトの宣言Dim typedRow As SampleDataset.publishersRow'テーブルの1行目を取得typedRow = typedTable(0)'pub_name列の値を取得pub_name = typedRow.pub_name'テーブルから直接1行目のpub_nameの列の値を取得pub_name = typedTable(0).pub_name
型付DataSet
http://biki.jp.net/enterprisenet
行(DataRow)・データへのアクセス
//行数の取得(0の場合は行がない)rowsCount = table.Rows.Count;//行オブジェクトの宣言DataRow row;//テーブルの1行目を取得row = table.Rows[0];//pub_name列の値を取得pub_name = (string)row["pub_name"];//テーブルから直接1行目の2番目の列(pub_name)の値を取得pub_name = (string)table.Rows[0][1];//テーブルから直接1行目のpub_nameの列の値を取得pub_name = (string)table.Rows[0]["pub_name"];
DataSet
http://biki.jp.net/enterprisenet
行(DataRow)・データへのアクセス
//行数の取得(0の場合は行がない)rowsCount = typedTable.Rows.Count;//型付行オブジェクトの宣言SampleDataset.publishersRow typedRow;//テーブルの1行目を取得typedRow = typedTable[0];//pub_name列の値を取得pub_name = typedRow.pub_name;//テーブルから直接1行目のpub_nameの列の値を取得pub_name = typedTable[0].pub_name;
型付DataSet
http://biki.jp.net/enterprisenet
リレーションを利用したアクセス
RowのGetChildRowsメソッド(親から子)・GetParentRowプロパティ(子から親)を利用してアクセス
型付DataSetではアクセス用メソッド・プロパティが提供される
….pub_namepub_id ….pub_namepub_id
SampleDataset
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)
GettitlesRows メソッド
publishersRow プロパティ
http://biki.jp.net/enterprisenet
リレーションを利用したアクセス(親から子テーブル)
'行オブジェクトの宣言Dim childRows() As DataRow'リレーション名がpublisherstitlesで関連している子の1つ目のtitle列の値を取得
childRows = parentRow.GetChildRows("publisherstitles")title = DirectCast(childRows(0)("title"), String)'上記をまとめて行う場合title = DirectCast(parentRow.GetChildRows("publisherstitles")(0)("title"), String)
'型付行オブジェクトの宣言Dim typedChildRows() As SampleDataset.titlesRow'関連しているtitlesテーブルの1つ目のtitle列の値を取得typedChildRows = typedParentRow.GettitlesRows()title = typedChildRows(0).title'上記をまとめて行う場合title = typedParentRow.GettitlesRows()(0).title
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
リレーションを利用したアクセス(子から親テーブル)
'行オブジェクトの宣言Dim parentRow As DataRow'リレーション名がpublisherstitlesで関連している親のpub_name値を取得parentRow = typedChildRows(0).GetParentRow("publisherstitles")pub_name = DirectCast(parentRow("pub_name"), String)'上記をまとめて行う場合pub_name = DirectCast(typedChildRows(0).GetParentRow("publisherstitles")("pub_name"), String)
'型付行オブジェクトの宣言Dim typedParentRow As SampleDataset.publishersRow'親テーブルpublishersのpub_name値を取得typedParentRow = typedChildRows(0).publishersRowpub_name = typedParentRow.pub_name'上記をまとめて行う場合pub_name = typedChildRows(0).publishersRow.pub_name
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
リレーションを利用したアクセス(親から子テーブル)
//行オブジェクトの宣言DataRow[] childRows;//リレーション名がpublisherstitlesで関連している子の1つ目のtitle列の値を取得
childRows = parentRow.GetChildRows("publisherstitles");title = (string)childRows[0]["title"];//上記をまとめて行う場合title = (string)parentRow.GetChildRows("publisherstitles")[0]["title"];
//型付行オブジェクトの宣言SampleDataset.titlesRow[] typedChildRows;//関連しているtitlesテーブルの1つ目のtitle列の値を取得typedChildRows = typedParentRow.GettitlesRows();title = typedChildRows[0].title;//上記をまとめて行う場合title = typedParentRow.GettitlesRows()[0].title;
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
リレーションを利用したアクセス(子から親テーブル)
DataRow parentRow; //行オブジェクトの宣言//リレーション名がpublisherstitlesで関連している親のpub_name値を取得parentRow = typedChildRows[0].GetParentRow("publisherstitles");pub_name = (string)parentRow["pub_name"];//上記をまとめて行う場合pub_name =(string)
typedChildRows[0].GetParentRow("publisherstitles")["pub_name"];
//型付行オブジェクトの宣言SampleDataset.publishersRow typedParentRow;//親テーブルpublishersのpub_name値を取得typedParentRow = typedChildRows[0].publishersRow;pub_name = typedParentRow.pub_name;//上記をまとめて行う場合pub_name = (string)typedChildRows[0].publishersRow.pub_name;
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
主キーを利用した行の検索
DataRowのFindメソッドを利用して行を検索
型付DataSetでは専用の検索メソッドが提供される
….pub_namepub_id ….pub_namepub_id
SampleDataset
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)
publishersDataTable.FindBypub_id メソッド
titlesDataTable.FindBytitle_id メソッド
検索
検索
http://biki.jp.net/enterprisenet
主キーを利用した行の検索
'行オブジェクトの宣言Dim row As DataRow'主キーの値が1389の行を取得row = table.Rows.Find("1389")
'型付行オブジェクトの宣言Dim typedRow As SampleDataset.publishersRow'主キーpub_idの値が1389の行を取得typedRow = typedTable.FindBypub_id("1389")
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
主キーを利用した行の検索
//行オブジェクトの宣言DataRow row;//主キーの値が1389の行を取得row = table.Rows.Find("1389");
//型付行オブジェクトの宣言SampleDataset.publishersRow typedRow;//主キーpub_idの値が1389の行を取得typedRow = typedTable.FindBypub_id("1389");
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
DataSetデータの編集
http://biki.jp.net/enterprisenet
行の追加
DataTableのNewRowメソッドを利用して行を追加
型付DataSetではテーブル毎の追加メソッドが提供される
….pub_namepub_id ….pub_namepub_id
SampleDataset
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)
publishersDataTable. AddpublishersRow メソッド
titlesDataTable. AddtitlesRow メソッド
追加
追加
http://biki.jp.net/enterprisenet
行の追加
'行オブジェクトの作成row = table.NewRow()'データの値の設定row("pub_id") = "pub_id1"row("pub_name") = "pub_name1"row("city") = "city1"row("state") = "state1"row("country") = "country1"'行オブジェクトのテーブルへの追加table.Rows.Add(row)
DataSet
'行オブジェクトのテーブルへの追加typedRow = typedTable.AddpublishersRow( _
"pub_id2", "pub_name2", "city2", "state2", "country2")
型付DataSet
http://biki.jp.net/enterprisenet
行の追加
//行オブジェクトの作成row = table.NewRow();//データの値の設定row["pub_id"] = "pub_id1";row["pub_name"] = "pub_name1";row["city"] = "city1";row["state"] = "state1";row["country"] = "country1";//行オブジェクトのテーブルへの追加table.Rows.Add(row);
DataSet
//行オブジェクトのテーブルへの追加typedRow = typedTable.AddpublishersRow("pub_id2", "pub_name2", "city2", "state2", "country2");
型付DataSet
http://biki.jp.net/enterprisenet
行の変更
行のアイテムに値を代入
….pub_namepub_id ….pub_namepub_id
SampleDataset
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)
新しい値
変更
http://biki.jp.net/enterprisenet
行の変更
'行オブジェクトの宣言Dim row As DataRow'行オブジェクトの取得row = table.Rows(0)'データの値の変更row("pub_name") = "pub_name1"row("city") = "city1"
'型付行オブジェクトの宣言Dim typedRow As SampleDataset.publishersRow'行オブジェクトの取得typedRow = typedTable(0)'データの値の変更typedRow.pub_name = "pub_name2"typedRow.city = "city2"
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
行の変更
//行オブジェクトの宣言DataRow row;//行オブジェクトの取得row = table.Rows[0];//データの値の変更row["pub_name"] = "pub_name1";row["city"] = "city1";
//型付行オブジェクトの宣言SampleDataset.publishersRow typedRow;//行オブジェクトの取得typedRow = typedTable[0];//データの値の変更typedRow.pub_name = "pub_name2";typedRow.city = "city2";
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
行の削除
DataRowのDeleteメソッドを利用して行を削除
….pub_namepub_id ….pub_namepub_id
SampleDataset
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)
削除
削除
http://biki.jp.net/enterprisenet
行の削除
'2番目の行オブジェクトの削除table.Rows(1).Delete()'主キーで行オブジェクトの削除Dim row As DataRowrow = table.Rows.Find("1389")row.Delete()
'主キーで行オブジェクトの削除Dim typedRow As SampleDataset.publishersRowtypedRow = typedTable.FindBypub_id("9999")typedRow.Delete()
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
行の削除
//2番目の行オブジェクトの削除table.Rows[1].Delete();//主キーで行オブジェクトの削除DataRow row;row = table.Rows.Find("1389");row.Delete();
//主キーで行オブジェクトの削除SampleDataset.publishersRow typedRow;typedRow = typedTable.FindBypub_id("9999");typedRow.Delete();
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
変更データの確定と破棄
変更の確定 AcceptChangesメソッド
変更の破棄 RejectChangesメソッド DataSet,DataTable,DataRow単位で利用可能
….pub_namepub_id ….pub_namepub_id
SampleDataset
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)
DataSet. AcceptChanges
DataSet. RejectChanges
DataTable. AcceptChanges
DataTable. RejectChanges
DataRow. AcceptChanges
DataRow. RejectChanges
http://biki.jp.net/enterprisenet
変更データの確定と破棄
Dim row As DataRowrow = table.Rows(0)row("pub_name") = "pub_name1"row("city") = "city1"'変更した行データの確定(行単位)row.AcceptChanges()
row = table.Rows(1)row("pub_name") = "pub_name1"row("city") = "city1"row = table.Rows(2)row("pub_name") = "pub_name1"row("city") = "city1"'変更したデータの確定(DataSet全体)ds.AcceptChanges()
http://biki.jp.net/enterprisenet
変更データの確定と破棄
Dim row As DataRowrow = table.Rows(0)row("pub_name") = "pub_name1"row("city") = "city1"'変更したデータの破棄(行単位)row.RejectChanges()
row = table.Rows(1)row("pub_name") = "pub_name1"row("city") = "city1"row = table.Rows(2)row("pub_name") = "pub_name1"row("city") = "city1"'変更したデータの破棄(DataSet全体)ds.RejectChanges()
http://biki.jp.net/enterprisenet
変更データの確定と破棄
DataRow row;row = table.Rows[0];row["pub_name"] = "pub_name1";row["city"] = "city1";//変更した行データの確定(行単位)row.AcceptChanges();
row = table.Rows[1];row["pub_name"] = "pub_name1";row["city"] = "city1";row = table.Rows[2];row["pub_name"] = "pub_name1";row["city"] = "city1";//変更したデータの確定(DataSet全体)ds.AcceptChanges();
http://biki.jp.net/enterprisenet
変更データの確定と破棄
DataRow row;row = table.Rows[0];row["pub_name"] = "pub_name1";row["city"] = "city1";//変更したデータの破棄(行単位)row.RejectChanges();
row = table.Rows[1];row["pub_name"] = "pub_name1";row["city"] = "city1";row = table.Rows[2];row["pub_name"] = "pub_name1";row["city"] = "city1";//変更したデータの破棄(DataSet全体)ds.RejectChanges();
http://biki.jp.net/enterprisenet
DataSetの利用
http://biki.jp.net/enterprisenet
データのマージ
DataSetのMergeメソッドを利用してデータをマージすることができる 利用可能なデータソースはDataSet、DataTableとDataRow配列
….pub_namepub_id ….pub_namepub_id
SampleDataset
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)
….pub_namepub_id ….pub_namepub_id
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)
Merge
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)
DataRow()
DataTable
DataSet
データソース
http://biki.jp.net/enterprisenet
データのマージ
'1つ目のDataSetにデータを読み込むDim targetDataSet As New SampleDataset()Dim adapterPublishers As New OleDbDataAdapter( _
"SELECT * FROM publishers", connectionString)adapterPublishers.Fill(targetDataSet.publishers)
'2つ目のDataSetにデータを読み込むDim srcDataSet As New DataSet()Dim adapterTitles As New OleDbDataAdapter( _
"SELECT * FROM titles", connectionString)adapterTitles.Fill(srcDataSet, "titles")
'1つ目のDataSetに2つ目のDataSetのデータをマージtargetDataSet.Merge(srcDataSet)
http://biki.jp.net/enterprisenet
データのマージ
//1つ目のDataSetにデータを読み込むSampleDataset targetDataSet = new SampleDataset();OleDbDataAdapter adapterPublishers = new OleDbDataAdapter(
"SELECT * FROM publishers", connectionString);adapterPublishers.Fill(targetDataSet.publishers);
//2つ目のDataSetにデータを読み込むDataSet srcDataSet = new DataSet();OleDbDataAdapter adapterTitles = new OleDbDataAdapter(
"SELECT * FROM titles", connectionString);adapterTitles.Fill(srcDataSet, "titles");
//1つ目のDataSetに2つ目のDataSetのデータをマージtargetDataSet.Merge(srcDataSet);
http://biki.jp.net/enterprisenet
行の特定バージョンへのアクセス
列の値にアクセス際に別バージョン(DataRowVersion ) を指定することで特定のバージョン行にアクセスできる 行の別のバージョンは行の編集後、行で AcceptChanges メソッドが呼び出される前にだけ存在。AcceptChangesメソッドの呼び出し後は、現在のバージョンと元のバージョンが同じになる
1 名前1 住所1 TEL1
1 名前1 住所2 TEL1
初期データ(RowState=Unchanged)
変更データ(RowState=Modified)
1 名前1 住所2 TEL1
確定データ(RowState= Unchanged )
①行のデータを変更
Original バージョン
Current バージョン
②変更データを確定
http://biki.jp.net/enterprisenet
行の特定バージョンへのアクセス
'行の状態を取得(Unchanged)stat = table.Rows(0).RowState'データの値の変更row = table.Rows(0)row("pub_name") = "pub_name1"'行の状態を取得(Modified)stat = table.Rows(0).RowState
'変更前データの取得(元データ)Dim originalPubName As String = _
DirectCast(row("pub_name", DataRowVersion.Original), String)'型付DataSetの場合originalPubName = _
DirectCast(typedTable(0)("pub_name", DataRowVersion.Original), String)
'変更データの確定row.AcceptChanges()'変更前データの取得(変更データ)originalPubName = DirectCast(row("pub_name", DataRowVersion.Original), String)
http://biki.jp.net/enterprisenet
行の特定バージョンへのアクセス
//行の状態を取得(Unchanged)stat = table.Rows[0].RowState;//データの値の変更row = table.Rows[0];row["pub_name"] = "pub_name1";//行の状態を取得(Modified)stat = table.Rows[0].RowState;
//変更前データの取得(元データ)string originalPubName = (string)row["pub_name", DataRowVersion.Original];
//型付DataSetの場合originalPubName = (string)typedTable[0]["pub_name", DataRowVersion.Original];
//変更データの確定row.AcceptChanges();//変更前データの取得(変更データ)originalPubName = (string)row["pub_name", DataRowVersion.Original];
http://biki.jp.net/enterprisenet
DataRowVersionの値
DataRowStateの値
DataRowState ・DataRowVersion
Current この行には現在の値が格納されています
Default 現在の DataRowStateに従った既定の行バージョン
Original この行には元の値が格納されています
Proposed この行には提示された値が格納されています
Added 行が DataRowCollection に追加されましたが、 AcceptChanges が呼び出されていません
Deleted DataRow の Delete メソッドを使用して行が削除されました
Detached 行が作成されましたが、どの DataRowCollection にも追加されていません。 DataRow は、作成された直後からコレクションに追加されるまでの間、またはコレクションから削除された場合に、この状態になります
Modified 行が変更されましたが、 AcceptChanges が呼び出されていません
Unchanged 前回 AcceptChanges が呼び出されて以降、この行は変更されていません。
http://biki.jp.net/enterprisenet
変更された行の取得
DataSet(もしくはDataTable)のGetChangesメソッドを利用して変更されたレコードだけをデータセットから抽出できる
pub_id pub_name …
.
1 名前1
2 名前2X
3 名前3
pub_id pub_name ….
2 名前2XGetChanges
変更された行
http://biki.jp.net/enterprisenet
変更された行の取得スマートクライアントでの利用例
pub_id pub_name ….
1 名前1
2 名前2X
3 名前3
pub_id pub_name ….
2 名前2X
③ GetChanges
pub_id pub_name ….
1 名前1
2 名前2
3 名前3
②データの変更pub_id pub_name ….
1 名前1
2 名前2X
3 名前3
pub_id pub_name ….
1 名前1
2 名前2
3 名前3
pub_id pub_name ….
2 名前2X
④転送
①転送
⑤マージ
Web サーバークライアント
http://biki.jp.net/enterprisenet
変更された行の取得
'編集用のコピーDataSetを作成(クライアントの取得)copyDataSet.Merge(orignalDataSet)
'DataSetの値の変更(クライアントでの編集)copyDataSet.publishers(0).pub_name = "pub_name1"
'差分データの取得(転送データの作成)Dim changeDataSet As SampleDatasetchangeDataSet = DirectCast(copyDataSet.GetChanges(), SampleDataset)MessageBox.Show("差分データ = " + changeDataSet.GetXml())
'元データへの差分データの反映(サーバーへの反映)orignalDataSet.Merge(changeDataSet)
http://biki.jp.net/enterprisenet
変更された行の取得
//編集用のコピーDataSetを作成(クライアントの取得)copyDataSet.Merge(originalDataSet);
//DataSetの値の変更(クライアントでの編集)copyDataSet.publishers[0].pub_name = "pub_name1";
//差分データの取得(転送データの作成)SampleDataset changeDataSet;changeDataSet = (SampleDataset)copyDataSet.GetChanges();MessageBox.Show("差分データ = " + changeDataSet.GetXml());
//元データへの差分データの反映(サーバーへの反映)originalDataSet.Merge(changeDataSet);
http://biki.jp.net/enterprisenet
データのフィルタとソート
DataViewを利用して1つのDataTableをフィルタしたりソートすることができる 複数のDataTableをJoinするようなDataViewは作成できないため、
DataColumnのExpressionを利用した他のテーブル列を取り込んだDataTableをあらかじめ作成しておく
….pub_namepub_id ….pub_namepub_id
SampleDataset
publishers テーブル(親)
… commentPub_id…titleTitle_id … commentPub_id…titleTitle_id
titles テーブル(子)
Title_id title … Pub_id … comment
DataView
フィルタ:DataView.RowFilterプロパティソート:DataView.Sortプロパティ
http://biki.jp.net/enterprisenet
データのフィルタとソート
'DataViewを利用したフィルタDim dv As New DataView()dv.Table = tabledv.RowFilter = "country='USA'"
'DataViewを利用したソートDim dv As New DataView()dv.Table = tabledv.Sort = "pub_name"
http://biki.jp.net/enterprisenet
データのフィルタとソート
//DataViewを利用したフィルターDataView dv = new DataView();dv.Table = table;dv.RowFilter = "country='USA'";
//DataViewを利用したソートDataView dv = new DataView();dv.Table = table;dv.Sort = "pub_name";
http://biki.jp.net/enterprisenet
カラムの絞り込みと Distinct
DataViewのToTableを利用すると、元のデータの一部のカラムを取り出すことができる
さらに、同じデータを1つにまとめることもできます(Distinct機能 )
'DataViewを利用したDistinctDim view As DataView = New DataView(table)Dim newTable As DataTable = view.ToTable(“UniqueData”, True,"Category", "QuantityInStock")
//DataViewを利用した DistinctDataView view = new DataView(table); DataTable newTable = view.ToTable("UniqueData", true, "Category", "QuantityInStock");
http://biki.jp.net/enterprisenet
DataSet応用&Tips
http://biki.jp.net/enterprisenet
DBNullのハンドリング
DataColumnのプロパティ AllowDBNull
この列に null (VBでは Nothing)値を格納できるかどうかを示す値
DefaultValue 新しい行を作成するときに使用されるこの列の既定値
DataTableへの行追加時に便利 DataTableのNewRowで作成した行に既定値が設定される
注意 データベースから読み出したNULL値は置換されない
後述するデザイナで指定するNullValueを利用
http://biki.jp.net/enterprisenet
DBNullのハンドリング
型付DataSet デザイナでの設定(続き) NullValue
(Throw Exception)(既定値)を指定するとアクセス時にDBNullであれば例外をスロー
(Null) を指定するとDBNullであればnull (VBでは Nothing)を返す (Empty)を指定するとDBNullであればString.Emptyを返す。ただし、文字例の場合のみ指定可能。
その他の値を指定するとDBNullであればその値が返される。 NullValueの利用上の注意
NullValueは型付DataSetで作成されたプログラム上で実現されている機能であり、あくまでも型付DataSetのクラスの生成されたプロパティをアクセスした場合にのみ有効であることに注意
○ typedTable(0).pub_name × table.Rows(0)(“pub_name”) ← DBNullが返える
http://biki.jp.net/enterprisenet
参考デザイナで指定可能なカラムのプロパティ
http://biki.jp.net/enterprisenet
DBNullの判断と設定
'' DBNull判定If table.Rows(0).IsNull("pub_name") Then
...End If'' DBNull設定table.Rows(0)("pub_name") = System.Convert.DBNull
'' DBNull判定If typedTable(0).Ispub_nameNull() Then
...End If'' DBNull設定typedTable(0).Setpub_nameNull()
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
DBNullの判断と設定
//DBNull判定if (table.Rows[0].IsNull("pub_name")){}//DBNull設定table.Rows[0]["pub_name"] = System.Convert.DBNull;
//DBNull判定if (typedTable[0].Ispub_nameNull()) {}//DBNull設定typedTable[0].Setpub_nameNull();
型付DataSet
DataSet
http://biki.jp.net/enterprisenet
データセットのデータの検証
DataSet自体にデータの有効性の確認を組み込むことができる。主な組み込み方法としては以下の3つ。 制約を利用したデータ検証
キー制約や一意の制約などをデータセットの実際のスキーマ定義の一部として作成する
DataColumnのプロパティの設定
MaxLength、AllowDBNull、Unique など、DataColumn オブジェクトのプロパティを設定する
変更イベントのハンドリング
列および行の変更イベント中にデータをチェックできるアプリケーション固有の検証を作成する
DataGrid(Windowsフォーム)などのデータセットの更新がUIで直接実行される場合に利用されることが多い
http://biki.jp.net/enterprisenet
データセットのデータの検証制約を利用したデータ検証
主キー NULL でない一意な値を持つ列(1つ以上)として定義することができる。
デザイナで「新しいキー」を追加することで定義することが可能。
一意キー(UniqueConstraint) NULL 値を許可する、一意な値を持つ列(1つ以上)として定義することができる。
デザイナで「新しいキー」を追加することで定義することが可能。1テーブル複数個作成可能。主キーは1つのみ。
http://biki.jp.net/enterprisenet
データセットのデータの検証制約を利用したデータ検証
キー参照(ForeignKeyConstraint) データベースの外部キーと似たもので、関連付けられているテーブルの更新や追加、削除を制限することができる。
例えば、子供を持つ親レコードの削除の禁止。
デザイナでリレーションを作成して外部キー制約を利用することで可能。DeleteRuleやUpdateRule プロパティで動作を変更することが可能。
http://biki.jp.net/enterprisenet
データセットのデータの検証DataColumnのプロパティの設定
MaxLength
文字単位で表した列の最大長。列に最大長がない場合の値は -1 (既定)
AllowDBNull
null 値を格納できる場合は true(既定値)
Unique
値が一意である必要がある場合は true 。既定値はfalse
DataSetデザイナで指定する場合は該当列をキーとして設定するとtrueに設定される
http://biki.jp.net/enterprisenet
データセットのデータの検証制約の一時的な無効化
DataSet.EnforceConstraintsプロパティ DataSet更新処理で制約を有効/無効するプロパティ
trueの場合に自動的に制約のチェックが行われる
falseの場合は制約のチェックは行われない falseからtrueに設定した場合、全ての制約のチェックが行われ、制約に違反していると例外が発生する
DataTableのConstrains制約、DataColumnの制約に対して影響
キー参照が設定されているDataSetに対して、制約を一時的に無効化してテーブルからデータを読み出す例
ds.EnforceConstraints = FalsedaCustomers.Fill(ds)daOrders.Fill(ds)ds.EnforceConstraints = True
ds.EnforceConstraints = false;daCustomers.Fill(ds);daOrders.Fill(ds);ds.EnforceConstraints = true;
http://biki.jp.net/enterprisenet
データセットのデータの検証変更イベントのハンドリング
ColumnChanging イベント 特定の列の変更を検証する場合に利用。
列の変更直後にエラーを検出することが必要な場合は、ColumnChanging イベントを使って検証。
RowChanging イベント 変更が行のどこかで発生していることを通知。
一度に複数のエラーを検出する場合 RowChanging イベントを利用。特に、1 つの列の値が別の列の内容に基づいて検証されるような方法でデータが構築されている場合は、RowChanging イベント中に検証を実行する必要がある。
一時的に制約を中断する目的でDataRowのBeginEdit メソッドを利用すると、各列がそれぞれ変更された後のRowChanging イベントおよび RowChanged イベントをオフにすることができる。EndEdit メソッドが呼び出されるまで発生しない。
http://biki.jp.net/enterprisenet
データセットのデータの検証変更イベントのハンドリング
Private Sub table_ColumnChanging( _ByVal sender As Object, ByVal e As DataColumnChangeEventArgs)
''発生したカラム名の確認If e.Column.ColumnName = "pub_name" Then
Dim newValue As String = DirectCast(e.ProposedValue, String)If newValue.Trim().Length > 10 ThenMessageBox.Show("10文字以下で入力してください", "入力エラー")Throw New ApplicationException("10文字以下で入力してください")
End IfEnd If
End Sub
http://biki.jp.net/enterprisenet
データセットのデータの検証変更イベントのハンドリング
private void table_ColumnChanging(object sender, DataColumnChangeEventArgs e)
{
//発生したカラム名の確認if (e.Column.ColumnName == "pub_name") {string newValue = (string)(e.ProposedValue);if (newValue.Trim().Length > 10) {
MessageBox.Show("10文字以下で入力してください","入力エラー");throw new ApplicationException("10文字以下で入力してください");
}}
}
http://biki.jp.net/enterprisenet
DataSet Tips
DataSetの検索メソッドの利用について
主キーで検索する場合 DataRowCollection.Findメソッドを利用(DataTable.Rows.Findのこと) DataTableには主キーで検索インデックスが生成される
任意の項目・特定バージョンの検索 DataTable.Selectメソッドが利用できる。ただし、Selectメソッドは複雑な検
索が可能な反面オーバーベッドも大きいため、同じ項目を何度も等号検索する処理にはDataViewを作成・利用した検索を行うようにする。
DataViewを利用した検索 DataViewのSortカラムに指定した項目にたいしてFindおよびFindRowsメ
ソッドで検索が可能です。(検索インデックスが生成され利用される) DataViewの検索インデックスはSort、RowFilter 、RowStateFilter プロパ
ティを変更するごとに再作成されるためコンストラクタで必要な値を全て指定するようにする。
RowStateFilterを利用した検索も可能だが検索インデックスが再作成されるためオーバーヘッドが大きくなる。DataGridなどでのフィルタ処理に利用する。
http://biki.jp.net/enterprisenet
DataSet TipsDataSetでの検索時の大文字・小文字の区別
SelectやFindメソッドなどはDataTableやDataSetのCaseSensitiveによって区別する/しないが変化する。既定値ではfalseのため大文字/小文字の区別をしない。
ユニークキーのチェックも同様の影響を受ける
型付DataSetに対してはデザイナで設定することが可能。
http://biki.jp.net/enterprisenet
DataSet TipsPartial Classの利用
Partialクラスとは 1つのクラスのソースコードを複数のファイルに分散して記述することができるコンパイラの仕組み
Partialクラスを利用することで型付DataSetに新しいプロパティやメソッドを追加することできる DataRow(テーブル名Row)クラスにプロパティを追加すると、データカラムのように利用することが可能
ただし、あくまでも型付DataSetに追加するものなので、非型付DataSetからは利用できない
http://biki.jp.net/enterprisenet
DataSet TipsPartial Classの利用
独自の計算式などを実装することが可能 画面のデータバインド処理に便利
partial class AuthorsData {partial class authorsRow {
public int TitleCount {get { return this.GettitleauthorRows().Length; }
}}
}
Partial Class AuthorsDataSetPartial Class authorsRow
Public ReadOnly Property TitleCount() As IntegerGet
Return Me.GettitleauthorRows().LengthEnd Get
End PropertyEnd Class
End Class
http://biki.jp.net/enterprisenet
DataSet Tipsシリアライズ
シリアライズの2つのパターン
XMLシリアライズ(XmlSerializerを利用したシリアライズ)
Diffgram形式
DiffGramは、データ要素の現在のバージョンと元のバージョンを識別するXML 形式です。行エラー情報、行順序などの情報も含まれています。
Binaryシリアライズ( BinaryFormatterを利用したシリアライズ)
RemotingFormatを設定することで出力形式を変えることが可能
下位互換のためXml形式が規定値。バイナリ形式で出力するためには明示的にSerializationFormat. Binaryを指定する必要がある
シリアライズの高速化
データが多くなるとBinaryシリアライズの方が高速
SchemaSerializationModeをExcludeSchemaにするとスキーマ情報がシリアライズされないため高速