「ほっ」と。キャンペーン
タグ:ADO.Net ( 21 ) タグの人気記事
(.Net)long→object→intへのキャスト時の注意
DataTable.Compute("SUM(clm1)") を使って、DataTableの集計値を求めたいと思ってました。
(DataTableのclm1列は int 型です。DataTable.Computeについては、(.Net)DataTableで特定の列の値を集計する参照。)

で下記のようなコードにすると InvalidCastException 例外が発生し、"指定されたキャストは有効ではありません。"と怒られます。。(C#)

//tblはDataTableインスタンス
int i = tbl.Compute("SUM(clm1"),null);

デバッガのウォッチ式で覗いてみると、DataTable.Compute は object 型で返り、内部では long 型となっているようです。
で、ちょっと実験をしてみました。

object o = new object() ;
long l = 50000;
int i = 0;
 
i = (int)l;
Console.WriteLine("long→int:" + i.ToString());
 
o = l;
Console.WriteLine("long→object:" + o.ToString());
 
i = (int)o; // ← ここで例外発生
Console.WriteLine("long→object→int:" + i.ToString());

long から int へは暗黙的キャストされますが、内部的に long 型の値を object に入れると object から int へのキャストはダメなようです。

下記のように、一旦 object から long に、そして int にキャストするとちゃんと動くようになりました。

i = (int)(long)o;
Console.WriteLine("long→object→long→long→int:" + i.ToString());


まぁ、当たり前といえば当たり前かもしれませんが、ちょっとハマりましたね。
DataTable.Compute が long を返すのも驚きです。(集計列は int なのに。。)

また、最近まで知りませんでしたが、 C# にはキャストに as 演算子というものが使えるようです。(参照型でしか使えませんが。。。)
as 演算子については@IT:.NET TIPS as演算子とキャストの違いはがわかりやすいです。
[PR]
by jehoshaphat | 2010-09-20 20:11 | .Net開発 | Trackback | Comments(0)
(.Net)DataTableとXMLの連携
今まで小規模なスタンドアロンアプリケーション作ってた時は、データベースとして MDB を使ってきたんですが、簡単なマスタ程度の情報であればわざわざMDB使わなくても、XMLでできるんじゃないかと思ってやってみました。

まず、XMLの情報を DataTable として扱えるかどうかですが、これはかなり簡単にできるようです。

XMLのスキーマ(テーブル定義情報)を作って、後はデータの入ったXMLを読み込ますだけみたいですね。

XMLスキーマで、テーブル定義した例です。
<?xml version="1.0" standalone="yes"?>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="corporation" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="corporation">
<xs:complexType>
<xs:sequence>
<xs:element name="id" type="xs:int" minOccurs="0" />
<xs:element name="name" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>

これで、"corporation"テーブルに、"id"列(int型) と "name"列(string)があることが定義されます。

実際のデータとして保存されるXMLはこんな感じです。
<?xml version="1.0" standalone="yes"?>
<DocumentElement>
<corporation>
<id>1</id>
<name>ホゲ株式会社</name>
</corporation>
<corporation>
<id>2</id>
<name>MEC株式会社</name>
</corporation>
<corporation>
<id>3</id>
<name>常世田自動車</name>
</corporation>
</DocumentElement>

このXMLを読み込むときは下記のように、まずスキーマを読み込んで、後データが入ってるXMLを読み込めばいいようです。

DataTable tbl = new DataTable();
tbl.ReadXmlSchema(@"C:\schema.xml");
tbl.ReadXml(@"C:\test.xml");

DataTable.ReadXmlSchema() でスキーマを読み込み、DataTable.ReadXml() でデータを読み込むという感じですね。
出力するときも、 DataTable.WriteXmlSchema() と DataTable.WriteXml() のメソッド使えば簡単にできるようです。

DataTable だけでなく、DataSet クラスにも ReadXmlSchema() , ReadXml() , WriteXmlSchema() , WriteXml() メソッドはあるので、複数のテーブルを扱う場合は、こっちを使った方が楽ですね。
この場合、DataSet で一つのXMLファイルになります。

ちなみに、DataSetのスキーマはこんな感じになります。
複数のテーブルが一ファイルにまとまってますよね。
<?xml version="1.0" standalone="yes"?>
<xs:schema id="testDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="testDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
 
<xs:element name="corporation">
<xs:complexType>
<xs:sequence>
<xs:element name="id" type="xs:int" minOccurs="0" />
<xs:element name="name" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
 
<xs:element name="testTbl">
<xs:complexType>
<xs:sequence>
<xs:element name="no" type="xs:int" minOccurs="0" />
<xs:element name="name" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
 
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>


スキーマ作るのが面倒な場合は、一旦 DataTable や DataSet の列定義を C# なり、VB.Net なりでおこなって、それを WriteXmlSchema() してやればいいかもしれません。

参考:
ADO.NET入門記-012 (DataSetにてXMLデータを扱う
[PR]
by jehoshaphat | 2010-06-07 08:54 | .Net開発 | Trackback | Comments(0)
(.Net)DataTableのリレーションPart2(コードだけでする方法)
(.Net)DataTable のリレーションPart1(デザイナを使った方法)の続きです。

コードだけでする方法
デザイナを使わずにリレーションを張るには、DataSet.Relations コレクションに、DataRelation インスタンスを追加すればいいようです。
こんな感じです。
テーブル構造データは前回と同じです。

private void button2_Click(object sender, EventArgs e)
{
//DataSet作成
DataSet dset = new DataSet();
//DataTable(position)作成
DataTable tblPosition = new DataTable("position");
tblPosition.Columns.Add(new DataColumn("id"));
tblPosition.Columns["id"].DataType = Type.GetType("System.Int32");
tblPosition.Columns.Add(new DataColumn("position_name"));
dset.Tables.Add(tblPosition);
//DataTable(staff)作成
DataTable tblStaff = new DataTable("staff");
tblStaff.Columns.Add(new DataColumn("id"));
tblStaff.Columns["id"].DataType = Type.GetType("System.Int32");
tblStaff.Columns.Add(new DataColumn("staff_name"));
tblStaff.Columns.Add(new DataColumn("position_id"));
tblStaff.Columns["position_id"].DataType = Type.GetType("System.Int32");
dset.Tables.Add(tblStaff);
//DataTable(position)にデータを追加
tblPosition.Rows.Add(new object[] { 1, "営業部" });
tblPosition.Rows.Add(new object[] { 2, "開発部" });
tblPosition.Rows.Add(new object[] { 3, "サポート部" });
//DataTable(staff)にデータを追加
tblStaff.Rows.Add(new object[] { 1, "山田太郎", 1 });
tblStaff.Rows.Add(new object[] { 2, "新岡明里", 1 });
tblStaff.Rows.Add(new object[] { 3, "遠野貴樹", 2 });
tblStaff.Rows.Add(new object[] { 4, "目黒亜由", 3 });
 
//リレーションを張る
dset.Relations.Add(
new DataRelation("position_staff",
tblPosition.Columns["id"],
tblStaff.Columns["position_id"])
);
 
//staffテーブルと外部キーに対応する親のpositionのデータ出力
foreach (DataRow row in tblStaff.Rows)
{
DataRow fkRow = row.GetParentRow("position_staff");
Console.Write(row["staff_name"].ToString() + " ");
Console.Write(fkRow["position_name"].ToString() + "\n");
}
Console.WriteLine();
 
//positionテーブルと外部キーに対応する子のstaffのデータ出力
foreach (DataRow row in tblPosition.Rows)
{
Console.WriteLine(row["position_name"].ToString() + "に所属するStaff");
DataRow[] fkRows = row.GetChildRows("position_staff");
foreach (DataRow fkRow in fkRows)
{
Console.WriteLine(" " + fkRow["staff_name"].ToString());
}
}
}

リレーション張れると、やはり便利ですね。

ただ、DataTable は一つの DataSet にか属せないのでそこは注意が必要です。

また、リレーションを張った DataTable を DataSet.Tables.Clear() でクリアするときは、その前に DataSet.Relations.Clear() でリレーションをクリアし、DataTable.Constraints.Clear() で制約を削除する必要があります。


参考:
MSDN:方法 : 関連する DataTable のレコードにアクセスする
MSDN:10 行でズバリ !! リレーショナルデータテーブルの構築 (VB)
[PR]
by jehoshaphat | 2010-06-05 00:40 | .Net開発 | Trackback | Comments(0)
(.Net)DataTableのリレーションPart1(デザイナを使った方法)
今まで使ったことないのですが、DataTableにはリレーショナルデータベースのように、リレーションが張れるようです。

ということで、ちょっと使ってみました。

デザイナを使った方法
下記のような構成テーブルのデータベース(今回はmdb)を用意し、VisualStudioに読み込ませて、DataSetを作成します。

●positionテーブル
・id列
・position_name列

●staffテーブル
・id列
・staff_name列
・position_id列

テストデータは下記のようにしてみました。

positionテーブル
┌─┬───────┐
│id│position_name │
├─┼───────┤
│1 │営業部 │
├─┼───────┤
│2 │開発部 │
├─┼───────┤
│3 │サポート部 │
└─┴───────┘

staffテーブル
┌─┬─────┬──────┐
│id│staff_name│position_id │
├─┼─────┼──────┤
│1 │山田太郎 │1 │
├─┼─────┼──────┤
│2 │新岡明里 │1 │
├─┼─────┼──────┤
│3 │遠野貴樹 │2 │
├─┼─────┼──────┤
│4 │目黒亜由 │3 │
└─┴─────┴──────┘


positionテーブルとstaffテーブルは1対多の関係で、staff テーブルの posion_id 列で関係づけられています。

デザイナを使った場合、リレーションシップはマウスで簡単に作成できます。
下記(db1DataSet)のような感じです。
e0091163_035951.jpg

子テーブルの DataRow から親テーブルの該当する DataRow を呼び出すには、DataRow.GetParentRow(リレーション名) とすればいいようです。
逆に、親テーブルのDataRow から子テーブルの該当する DataRow を呼び出すには、DataRow.GetChildRows(リレーション名) とすればいいようです。

サンプルはこんな感じです。(C#)
private void button1_Click(object sender, EventArgs e)
{
//テーブルアダプタインスタンス生成
db1DataSetTableAdapters.staffTableAdapter adpStaff =
new db1DataSetTableAdapters.staffTableAdapter();
db1DataSetTableAdapters.positionTableAdapter adpPosition =
new db1DataSetTableAdapters.positionTableAdapter();
 
//データセットインスタンス生成
db1DataSet dset = new db1DataSet();

//DBより各テーブルにデータ取得
adpStaff.Fill(dset.staff);
adpPosition.Fill(dset.position);
 
//staffテーブルと外部キーに対応する親のpositionのデータ出力
foreach (DataRow row in dset.staff)
{
DataRow fkRow = row.GetParentRow("position_staff");
Console.Write(row["staff_name"].ToString() + " ");
Console.Write(fkRow["position_name"].ToString() + "\n");
}
Console.WriteLine();
 
//positionテーブルと外部キーに対応する子のstaffのデータ出力
foreach (DataRow row in dset.position)
{
Console.WriteLine(row["position_name"].ToString() + "に所属するStaff");
DataRow[] fkRows = row.GetChildRows("position_staff");
foreach (DataRow fkRow in fkRows)
{
Console.WriteLine(" " + fkRow["staff_name"].ToString() );
}
}
}

出力はこのようになります。

山田太郎 営業部
新岡明里 営業部
遠野貴樹 開発部
目黒亜由 サポート部

営業部に所属するStaff
山田太郎
新岡明里
開発部に所属するStaff
遠野貴樹
サポート部に所属するStaff
目黒亜由


次はコードだけでする方法ですが、それについては、(.Net)DataTableのリレーションPart2(コードだけでする方法)に書きます。
[PR]
by jehoshaphat | 2010-06-05 00:39 | .Net開発 | Trackback | Comments(0)
(.Net)mdbを使うプログラムで Jet.OLEDB.4.0 の例外が出た

.Netでmdb(Access)をデータベースともつプログラムを作ってました。
このプログラムはターミナルサーバ(Windows Server 2003 x64)上で動かします。

開発用PC(XP x86)では問題なく動いてたので、実環境となるターミナルサーバ上で動かすとDB接続部分で下記のような例外が発生しました。

'Microsoft.Jet.OLEDB.4.0' プロバイダは
ローカルのコンピュータに登録されていません


ググるとこちらここで答えが載ってました。

そういえば、ビルド構成は Any CPU にしてました。つまり、x64環境では64bitで動くような構成になってたわけですね。
しかし、x64のWindowsではx64用の JET.OLEDB プロバイダは無く、呼び出し時にエラーとなった模様です。

で、回避策としては .Net アプリケーションを x86 構成でビルドすることです。
そうすると32bit版の OLEDB プロバイダを使ってくれるようです。
[PR]
by jehoshaphat | 2010-01-08 00:55 | .Net開発 | Trackback | Comments(0)
OLEDB JETでクエリを投げると、式が複雑すぎますと怒られた

ADO.Net を使って MDBへ のクエリ実行時に「式が複雑すぎます。」という例外で怒られました。

確かに、WHERE句に相当数の条件を入れています。
例えばこんな感じ。(パラメータクエリを使ってます。詳しくは(ADO.Net)OLEDB経由でのMDBへの副問い合わせにパラメータクエリを使うとおかしくなることがある)

PARAMETERS
pCondBirthday1 Char ,
pCondBirthday2 Char ,
pCondBirthday3 Char ,
pCondPref1 Text ,
pCondPref2 Text ,
pCondPref3 Text ;
SELECT *
FROM Customer
WHERE
(
Birthday = pCondBirthday1 OR
Birthday = pCondBirthday2 OR
Birthday = pCondBirthday3 OR
[省略]
) AND (
Pref = pCondPref1 OR
Pref = pCondPref2 OR
Pref = pCondPref3 OR
[省略]
)

どうやら WHERE句に条件大量にあるとダメみたいです。具体的のどれくらいの数を超えたらNGかというのは見つかりませんでした。

で、上記のSQLの場合、特に一つのフィールドに対して複数の OR 条件が大量の設定してます。
これは IN句を使うべきと同僚に言われてました。
言われてみれば、そんなのもあったなと。。今まで、副問い合わせで複数値が返るときにか使ってませんでした。。

ということで、下記のように OR 条件を IN句に置き換えたらエラーはでなくなりましたとさ。
(パラメータ定義部分は省略)

SELECT *
FROM Customer
WHERE
Birthday IN ( pCondBirthday1 ,
pCondBirthday2 ,
pCondBirthday3 ,
[省略]
)
AND
Pref IN ( pCondPref1 ,
pCondPref2 ,
pCondPref3 ,
[省略]
)

ま、結局は3流PGのSQLの知識不足ということでした。

参考:
「式が複雑すぎます」の具体的な条件
[PR]
by jehoshaphat | 2009-08-02 01:13 | SQL | Trackback | Comments(0)
AccessとOLEDB JET経由でLIKE文のワイルドカードが変わる

Access で LIKE 演算子で0文字以上の文字を表す時は * を使いますよね。
ところが、JETエンジン使って mdb にアクセスする OLEDB経由の ADO.Net だと % という純粋なSQLに近い形しないとダメなようです。

/*Accessだとヒットする。 OLEDB経由だとヒットしない*/
SELECT *
FROM Customer
WHERE Address LIKE '*京都*'
 
/*Accessだとヒットしない。 OLEDB経由だとヒットする*/
SELECT *
FROM Customer
WHERE Address LIKE '%京都%'


Access でテスト用のクエリを書いて、.Net のコードに移植してたんですが、これに気付かずちょっとハマってしまいした。
Visual Studio 上のサーバエクスプローラから mdf ファイルを指定し、クエリたたけば OLEDB 経由になるので、これからはこっち使ったほうが安全ですね。

この仕様については、Microsoft Jet SQL と ANSI SQL との比較で解説されてます。
下記の引用部分が、その仕様について言ってるところですね。
ANSI SQL のワイルドカード文字を使用できるのは、Jet 4.x と Microsoft OLE DB Provider for Jet を組み合わせて使う場合だけです。Microsoft Access または DAO を介して ANSI SQL のワイルドカード文字を使うと、リテラルとして解釈されます。Microsoft OLE DB Provider for Jet と Jet 4.x を使用しているときは、Jet SQL のワイルドカード文字がリテラルとして解釈されます。
[PR]
by jehoshaphat | 2009-07-31 12:39 | SQL | Trackback | Comments(0)
(ADO.Net)OLEDB経由でのMDBへの副問い合わせにパラメータクエリを使うとおかしくなることがある

OleDbCommand , OleDbDataAdapter オブジェクトを使って、SQLクエリを書いたんですが、どうも挙動がおかしいのです。
SQLには WHERE,FROM 句の中で副問い合わせ(サブクエリ)を多数使い、サブクエリ内で OleDbParameter を使いパラメータで抽出条件となる値を設定してます。

で、サブクエリを書いた位置によって、「抽出条件でデータ型が一致しません。」とかいうエラーがでたり、明らかに条件に一致するデータがあるのに抽出できなかったりとするのです。

どうやら何かの原因でパラメータの順序が入れ替わっているようです。
(もともと OLEDB のパラメータクエリは、プレースホルダを ? で表現し、OleDbCommand.Parameters に追加した順番で適用されます。)

いろいろ検索してると、MSサポート:OLE DB Provider for Jet 4.0 または Office 12.0 Access Database Engine OLE DB Provider を使用時にサブ クエリを持つパラメータ クエリを実行すると、予期しない結果を返す場合があるというのを見つけました。

どうやら、この問題は JET のバグっぽいですね。

対策としては、上記のページにあるようにメインのSQLクエリの前に
PARAMETERS p1 Text,p2 Long; SLECT ....
という感じで PARAMETERS を使い、ここで宣言したパラメータ変数(?)の順番で、パラメータを設定すればいいようです。


この原因探るのに数時間かかりました。この現象気付く人も結構少ないんじゃないでしょうか。。
バグってのはほんと勘弁してほしいですよね。
[PR]
by jehoshaphat | 2009-07-28 22:46 | .Net開発 | Trackback | Comments(0)
(ADO.Net)TableAdapter.Update を使っての新規レコードを追加でハマった
TableAdapter.Update を使えば簡単に新規レコードが追加できるんですが、はまってしまいました。

今までは更新前にDBのテーブルデータを DataTable として取得し、それに新しい DataRow を追加して、TableAdapter.Update(DataTable) を使って更新してたんですが、この方法だとオーバーヘッドが多すぎで効率的じゃありません。
MSDNみてると TableAdapter.Update(DataRow) ってのもあったんで、これだったらいけると思ってコーディングしてみました。
DataSetはこんな感じです。
e0091163_16525410.jpg

コードはこんな感じです。
DataSet1TableAdapters.ProductsTableAdapter adp = new DataSet1TableAdapters.ProductsTableAdapter();
DataSet1.ProductsDataTable tbl = new DataSet1.ProductsDataTable();
DataSet1.ProductsRow row = tbl.NewProductsRow();
row.ProductID = "aaa";
//テーブル更新
adp.Update(row);

これで実行してみましたが、DBに新規レコードができません。
あれっ?と思って、MSDN:方法 : データベースに新しいレコードを挿入するを眺めていると、DataTable に追加しないとダメなようです。
ということで、下記のようにしてみました。
DataSet1TableAdapters.ProductsTableAdapter adp = new DataSet1TableAdapters.ProductsTableAdapter();
DataSet1.ProductsDataTable tbl = new DataSet1.ProductsDataTable();
DataSet1.ProductsRow row = tbl.NewProductsRow();
row.ProductID = "aaa";
tbl.AddProductsRow(row);
//テーブル更新
adp.Update(row);

空であってもなくてもいったん DataTable にDataRow を追加してからでないと、TableAdapter.Update(DataRow) で更新しても挿入はしてくれないみたいですね。
コンパイルエラーも何も出ないので、気を付けてコーディングしないと見落としそうです。
[PR]
by jehoshaphat | 2009-06-13 16:53 | .Net開発 | Trackback | Comments(0)
(ADO.Net)DataSetを使ったトランザクション制御
(VB.Net)ADO.NetでOLEDBのトランザクションで、SQL直書き(コマンドオブジェクトにSLQ文をセットする方法)でのトランザクションの方法をメモりました。

今回は DataSet で作られた TableAdapter を使ってトランザクションを行う方法です。

まず、複数のクライアントが同時にDBにアクセスし不整合になるのを防ぐため、排他制御の仕組みをとらないといけません。
Visual Studio で DataSet を使うとこの仕組みもどうやら簡単に出来るようです。
Visual Studio のサーバーエクスプローラからテーブルを DataSet のデザイナにドラッグすると勝手に DataTable と TableAdpter を作成してくれますが、この時点で勝手に更新時(Update句)に楽観的ロックがかかるようになってます。
下記図のようにテーブルアダプタの詳細を見ると「オプティミスティック同時実行制御」にチェックが入ってると排他制御がかかります。
e0091163_9213963.jpg

ただ排他制御といっても楽観的ロックなので、更新時に条件として自身のDataSetがデータを取得した時から各フィールドが変更されていなかどうかをチェックしているだけです。
たとえば、上記図のようなテーブル(test2)だと、VisualStudio が作成する排他制御の入った Update 句はこうなります。

UPDATE test2
SET id = @id, name = @name, value = @value
WHERE (id = @Original_id) AND (@IsNull_name = 1) AND (name IS NULL) AND (@IsNull_value = 1) AND (value IS NULL)
OR
(id = @Original_id) AND (name = @Original_name) AND (@IsNull_value = 1) AND (value IS NULL)
OR
(id = @Original_id) AND (@IsNull_name = 1) AND (name IS NULL) AND (value = @Original_value)
OR
(id = @Original_id) AND (name = @Original_name) AND (value = @Original_value)

フィールド数が多いとかなりオーバヘッドがかかりそうなクエリです。

また、テーブルに timestamp 型のフィールド(SQL Serverの場合、timestamp型は行の挿入または更新時に自動的に値が更新されるもの)があると、これを更新時の比較条件に勝手します。
上記 test2 のテーブルにタイムスタンプ型の列 "updatecheck" を追加して、Visual Studio が生成した Update 句をみるとこうなっています。
e0091163_922206.jpg


UPDATE test
SET id = @id, name = @name, value = @value
WHERE (id = @Original_id) AND (@IsNull_updatecheck = 1) AND (updatecheck IS NULL)
OR
(id = @Original_id) AND (updatecheck = @Original_updatecheck)

条件が timestamp の列だけを比較して、他のユーザが先に更新していないかチェックするようになっています。
フィールド数が多いテーブルはこちらのタイムスタンプ型のチェックのほうが、前フィールドチェック型に比べてオーバヘッドは低くなりそうですね。

この辺の詳細はMSDN:オプティミスティック同時実行制御 (ADO.NET)で詳しく説明されてます。

さて、後は排他制御失敗時にロールバックするようにトランザクションをうまくからめるだけです。
トランザクションを開始して、各テーブルを更新。その時、排他制御に引っ掛かったら DBConcurrencyException が発生するので、そこでロールバックを行う。問題なければコミット。という流れになります。
その具体的なコードは下記の通りです。
コネクションとトランザクションのオブジェクトを TableAdpter オブジェクトに紐づけるという点がミソですね。
'テーブルアダプタのインスタンス生成
Dim adpTest As New RhythmSalesProDataSetTableAdapters.testTableAdapter()
Dim adpTest2 As New RhythmSalesProDataSetTableAdapters.test2TableAdapter()
 
Dim cn As SqlClient.SqlConnection = adpTest.Connection
'まずコネクションを開く
cn.Open()
' トランザクション開始
Dim trn As SqlClient.SqlTransaction = cn.BeginTransaction
 
Try
Dim tblTest As RhythmSalesProDataSet.testDataTable = adpTest.GetDataByID(1)
For Each row As DataRow In tblTest.Rows
row.Delete()
Next
'コネクションとトランザクションの指定
adpTest.Connection = cn
adpTest.Transaction = trn
'DB更新
adpTest.Update(tblTest)
 
Dim tblTest2 As RhythmSalesProDataSet.test2DataTable = adpTest2.GetDataByID(1)
For Each row As DataRow In tblTest.Rows
row.Delete()
Next
'コネクションとトランザクションの指定
adpTest2.Connection = cn
adpTest2.Transaction = trn
'DB更新
adpTest2.Update(tblTest2)
'コミット
trn.Commit()
Catch ex As DBConcurrencyException
' 同時実行違反の処理をここでする。。エラーメッセージとか。。。
'ロールバック
trn.Rollback()
Catch ex As Exception
'ロールバック
trn.Rollback()
Throw
Finally
cn.Close()
End Try

[PR]
by jehoshaphat | 2009-05-15 08:03 | .Net開発 | Trackback | Comments(0)