チュートリアル:同時実行例外の処理
http://msdn.microsoft.com/ja-jp/library/ms171936(VS.80).aspx
より。
エラーが発生しているレコードの値を元に、元のデータベースの(更新前の)レコードを取得し返す。
Exception.Rowの値を引数「RowWithError」として渡す。
private Datas.ds.MasterDataTable tempdt = new Datas.ds.MasterDataTable(); private Datas.ds.MasterRow[] tempr; private Datas.ds.MasterRow[] GetCurrentRowInDB(Datas.ds.MasterRow RowWithError) { this.ta_Master.Fill(tempdt); this.ta_Master.FillRow(tempdt, RowWithError.ID, RowWithError.MAKEDATE); Array.Resize<Datas.ds.MasterRow>(ref this.tempr, 1); tempr[0] = (Datas.ds.MasterRow)tempdt.Rows[0]; return tempr; }
指定されたバージョンの行の値を文字列に変換して返す。
private string GetRowData(Datas.ds.MasterRow row, DataRowVersion RowVersion) { string rowData = ""; rowData = "作成日 : " + String.Format("{0:yyyy/MM/dd HH:mm:ss}", row["MAKEDATE", RowVersion].ToString()) + " | " + "最終更新 : " + String.Format("{0:yyyy/MM/dd HH:mm:ss}", row["LASTDATE", RowVersion].ToString()) + " (" + row["LASTUSER", RowVersion].ToString() + ")"; return rowData; }
メッセージボックス(CreateMessage)で選択された回答値によって、データの保存処理を行う。
ここは振分だけを行い、実処理は下のUpdateDatabase()で。
private int ProcessDialogResult(DialogResult res, Datas.ds.MasterRow r) { int cnt = 0; switch (res) { case DialogResult.Yes: this.ds.Merge(this.tempr, true, MissingSchemaAction.Error); //cnt = this.ta_Master.Update(r); //cnt = this.UpdateDatabase(r); break; case DialogResult.No: this.ds.Merge(this.tempr); MessageBox.Show("更新がキャンセルされました。"); break; } return cnt; }
同時実行例外時に表示するエラーメッセージを生成。
private string CreateMessage(Datas.ds.MasterRow row) { Datas.ds.MasterRow[] r = this.GetCurrentRowInDB(row); Datas.ds.MasterRow or = r[0]; //return // "データベースの値 : " + this.GetRowData(or, DataRowVersion.Default) + Environment.NewLine + // "変更前の値 : " + this.GetRowData(row, DataRowVersion.Original) + Environment.NewLine + // "変更しようとしている値 : " + this.GetRowData(row, DataRowVersion.Current) + Environment.NewLine + // Environment.NewLine + // "データベースの値を、現在の値で置き換えますか?"; return "このデータは、他のユーザに保存されています。" + Environment.NewLine + Environment.NewLine + "データベースのデータ : " + this.GetRowData(or, DataRowVersion.Default) + Environment.NewLine + "変更前のデータ : " + this.GetRowData(row, DataRowVersion.Original) + Environment.NewLine + "変更しようとしたデータ : " + this.GetRowData(row, DataRowVersion.Current) + Environment.NewLine + Environment.NewLine + "画面を再読込してから、再度保存してみて下さい。"; }
実際のデータベース保存処理。
private int UpdateDatabase(Datas.ds.MasterRow r) { String msg = ""; int cnt = 0; try { // トランザクション処理を開始します。 using (System.Transactions.TransactionScope tx = new System.Transactions.TransactionScope()) { this.ta_Master.Connection.ConnectionString = "Data Source=datasourcename;Initial Catalog=DBNAME;Integrated Security=True"; cnt = this.ta_Master.Update(r); tx.Complete(); } return cnt; } catch (DBConcurrencyException ex) { msg = "他のユーザが保存したデータです"; MessageBox.Show(CreateMessage((Datas.ds.MasterRow)ex.Row), msg, MessageBoxButtons.OK); __logger.Debug(msg, ex); //cnt = this.ProcessDialogResult(res, (ds.MasterRow)ex.Row); return cnt; } catch (System.Transactions.TransactionException ex) { msg = "トランザクションエラーです。"; MessageBox.Show(msg + Environment.NewLine + "処理がタイムアウトした可能性があります。", "トランザクションエラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); __logger.Error(msg, ex); return -1; } catch (System.Data.SqlClient.SqlException ex) { msg = "SQL実行エラーです。"; MessageBox.Show(msg, "SQLエラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); __logger.Error(msg, ex); return -1; } catch (Exception ex) { msg = "判別不能のエラーです。"; MessageBox.Show(msg, "一般エラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); __logger.Error(msg, ex); return -1; } finally { // 接続文字列は読取専用に戻しておきます。 this.ta_Master.Connection.ConnectionString = "Data Source=datasourcename;Initial Catalog=DBNAME;Persist Security Info=True;User ID=readonlyuser;Password=password"; } }