- PR -

.net 同時実行違反

1
投稿者投稿内容
ボンバイエ
会議室デビュー日: 2003/12/11
投稿数: 7
投稿日時: 2003-12-11 21:54
Ultra Web Grid を使用して、DBを更新しようとしています。
グリッドで変更された行だけを取得して、DataSetに格納して、
そのDataSetをOleDbDataAdapterに渡して更新しようとしています。
しかし、更新時にExceptionが発生し、「同時実行違反」になってしまいます。
「更新された行の取得時にRowStateをModifiedにするために、一旦ダミーの値を入れ、AcceptChanges()した後に、本当の値を入れる」という特殊なことをしていますが、それが邪魔をしているのでしょうか。

グリッド変更時のイベントのコード
private void Uwg_UpdateCell(object sender, Infragistics.WebUI.UltraWebGrid.CellEventArgs e)
{
 DataSet ds = (DataSet)ViewState[DISP_DATA_KEY]; //データセットを取得

DataRow row=null;
DataTable table=null;

object key=e.Cell.Row.Cells.FromKey(Uwg.Bands[0].DataKeyField).ToString(); //行のキーの値を取得

table=ds.Tables[e.Cell.Band.BaseTableName]; //データソーステーブル取得

if (key!=null) row=table.Rows.Find(key); //キー項目取得

if (row == null)
{
//キーで項目がないとき新たに行作成
row = table.NewRow();
row[table.PrimaryKey[0].ColumnName] = key.ToString();
table.Rows.Add(row);
//
key=e.Cell.Row.Cells.FromKey(Uwg.Bands[0].DataKeyField).ToString(); //行のキーの値を取得
for (int i=0; i<table.Columns.Count; i++)
{
row[i] = e.Cell.Row.Cells[i].Value;
}
row[e.Cell.Column.Index]="$"; //ダミー文字
row.AcceptChanges();
}
updateDataSet(e, ref ds); //セルの値設定

ViewState[DISP_DATA_KEY] = ds; //データセットをhideで持つ
}

private void updateDataSet(CellEventArgs e, ref DataSet pDs)
{
DataRow row=null;
DataTable table=null;

object key=e.Cell.Row.Cells.FromKey(Uwg.Bands[0].DataKeyField).ToString(); //行のキーの値を取得

table=pDs.Tables[e.Cell.Band.BaseTableName]; //データソーステーブル取得

if (key!=null) row=table.Rows.Find(key); //キー項目取得

if(row!=null) row[e.Cell.Column.Index]=e.Cell.Value; //テーブル行に設定
}
で行を設定しています。

更新は
db.oleDbCon.Open(); //コネクションを開く
int retVal = oleAdap.Fill(ds); //検索する
で更新しています。

更新時にExceptionが発生し、「同時実行違反 : UpdateCommand によって 0 件処理されました。」といわれてしまいます。
原因がわかりません。
わかる方がいれば教えてください。
小野@どっとねっとふぁん
ぬし
会議室デビュー日: 2001/10/30
投稿数: 402
投稿日時: 2003-12-12 18:37
AcceptChangeを実行した時点で、DataSet上ではダミーのデータが
もともと存在しているデータだと思い込んでしまうのでは?

DataSetで更新する場合、DataSetが持っているもともとのデータと
現在のDB上のデータと比較することで同時実行違反かどうかの
判定を行っていると思う。
このため、上記のようにダミーのデータがもともとのデータだと
思い込ませるような特殊なことをやっていたら、同時実行違反と
みなされて当然のよーな。

違うかな?
ボンバイエ
会議室デビュー日: 2003/12/11
投稿数: 7
投稿日時: 2003-12-15 10:48
確かにそれっぽい動きはしますね。

ということはRowStateを変更して、DataSetでテーブルを更新しようとすると、
変更前の値を持っておかないといけないということですね。
変更前の値を持たずにうまくRowStateを変更する方法はないのでしょうか?

また、変更前の値を持たず、変更分のDataSetだけでUpdateメソッドを使用してテーブルを更新する方法はないのでしょうか?

わかる方がいらっしゃれば、教えてください。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2003-12-15 12:04
質問の意図がよくわからないのですが。

 UltraWebGridでも、それ単体でデータは持っていないのではないでしょうか。体験版をダウンロードして、かなり以前に消してしまいましたが、DataSetを参照させていたと思います。つまり、元のDataSetを参照として持っている以上、それはViewStateにも入っており、UltraWebGridの何らかのプロパティを参照すれば、元のDataSetが取り出せたと思います。そこに、「元の値」が入っているDataRowがあるのだから、それを利用すればいいのでは?
#使わないと決めた理由は、DataSetがそのままViewStateに入って
#ページが非常に重くなるから、だったと思う。
#DataGridと比較して非常に重たかった、のは確実。


 あと、ソースをそのまま掲載するより、流れにまとめてくださるとありがたいです。読んで理解する時間をかけなくてすみますから。また、この手の問題は、SQL文をどのように組み立てているかも問題になります。自動生成しているのか、開発者が生成しているのか。可能な範囲で掲載してください。
ボンバイエ
会議室デビュー日: 2003/12/11
投稿数: 7
投稿日時: 2003-12-15 17:52
わかりにくくてすみません。

やっていること----------
ページロードで、UltraWebGridで表示させるデータを取得し、
DataSourceプロパティに入れて、DataBindさせています。
UpdateCellイベントでDataSetの内容を変更し、
更新ボタンのイベントでDataSetを使用して、テーブルを更新しています。
---------------------

UltraWebGridで表示させているDataSetを取り出せるのですか?
UpdateCellイベントでUltraWebGridのDataSourceを参照するとNullになってしまいます。
UltraWebGridのデータをDataSetで取得できそうなプロパティやメソッドが見当たらなかったので、自分で対象データをViewStateに格納しようと思い、変更されたデータだけDataSetで格納したかったのです。
UltraWebGridがずっとDataSetを持っていて、その参照しているDataSetを取り出せるのであれば、その方法を教えていただきたい。
自分の調査が足りないのか、見当たりませんでした。

また、更新の方法は「OleDbCommandBuilder」クラスを使用して、SQLを自動作成し、「OleDbDataAdapter」の「Update」メソッドで更新しています。

更新部分のソース----------------
OleDbCommandBuilder cb = new OleDbCommandBuilder(oleAdap); //更新用SQL作成
int kensu = oleAdap.Update(pDs); //DB更新
-------------------------------

わかる方がいれば、お願いします。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2003-12-15 18:17
 UltraWebGridは消してしまったのでDataGridで見ると・・・あ、Nothingだ。失礼しました。


引用:

ボンバイエさんの書き込み (2003-12-15 17:52) より:

また、更新の方法は「OleDbCommandBuilder」クラスを使用して、SQLを自動作成し、「OleDbDataAdapter」の「Update」メソッドで更新しています。

更新部分のソース----------------
OleDbCommandBuilder cb = new OleDbCommandBuilder(oleAdap); //更新用SQL作成
int kensu = oleAdap.Update(pDs); //DB更新
-------------------------------


 CommandBuilderから関連するリンクをたどっていくと書いてあるのですが、CommandBuiiderが作るUpdate文、Delete文は、「オプティミスティック同時実行制御」といって、全ての列のデータが一致していなければなりません。つまり、
ID, DATA1, DATA2
----------------
1, aaaa1, bbbb1

というデータを、
1, cccc1, dddd1
に変更しようとすると、次のようなUPDATE文が作成されます。

UPDATE table1 SET ID=1, DATA1='cccc1', DATA2='dddd1'
WHERE ID=1 AND DATA1='aaaa1' AND DATA2='bbbb1'

 つまり、ここででている「同時実行」は、「同じSQL文で二回書き換えようとしている」とかの意味ではなく、「あなたが書き換えようとしてから、他の誰かが書き換えています」という、「人」系の同時実行です。


 DataViewにしまって、そこから取り出したDataTableに対して変更をかけるのでしたら、わざわざダミー値をいれる必要はないのでは?

 または、Update文、Delete文を提供すれば(CommandBuilderを使わなければ)解決すると思います。(たぶんInsertと3つとも提供してやる必要があると思う)
ボンバイエ
会議室デビュー日: 2003/12/11
投稿数: 7
投稿日時: 2003-12-15 18:46
UltraWebGridがただでさえ遅い上に、DataSetを全件ViewStateに持つと
件数が500件程度で動きがかなり遅くなってしまいます。
そこで、変更した行だけDataSetとしてViewStateに入れたい。
それで、変更前のデータを持とうと思わなかったので、ダミーを使用したのですが・・・

CommandBuilderクラスでご返信いただいたようなSQLを作成されてしまうと確かに駄目ですね。

SQLをこちらで書くしかないのでしょうか。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2003-12-15 21:57
 変更した行をViewSetに入れる、というのが、ちょっと。変更を検知した時点でデータベースに反映するのはNGということですね。また、ViewState以外にSessionというのもありますが、これもNG?
 そのほか、UltraWebGridの使用/仕様に関しては、GrapeCityに直接尋ねる方が早いと思います。

 CommandBuilderに関しては、MSDN内にも記述があったと思うのですが、使わない方が吉です。また、アテにしすぎると凶です。
1

スキルアップ/キャリアアップ(JOB@IT)