同時実行例外処理を実装する

チュートリアル:同時実行例外の処理
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";
    }
}