0

過去数日間に何度もコードを書き直したので、ここにはコードを含めません。これ以上気にする価値はないので、一般的な用語で問題を説明します。

C#で記述され、SQLサーバーデータベースに接続されたwinformsアプリケーションがあります。アプリケーションの特定の部分では、データベース内の多数のテーブルで最大10個のSQLコマンドを操作できますが、これは「オールオアナッシング」の状況であるため、1つのトランザクション内に含める必要があります。10個のコマンドのいずれかが失敗した場合、どのコマンドもコミットしないようにします。

複雑な要因は次のとおりです。

  1. 10個のsqlコマンドのそれぞれに複数のパラメーターがあります
  2. 一部のsqlcommandsはINSERTを使用し、後続のsqlcommandsの一部でサーバー生成IDを使用する必要があります。
  3. 一部のコマンドは同じデータを操作します。つまり、初期のコマンドはデータベースに新しいアイテムを挿入し、後のsqlcommandの1つは同じエントリを更新しようとします。

この問題は1週間のほとんどを費やしており、比較的進展が少ないように感じているので、助けていただければ幸いです。

編集:

sqlcommandsは元々異なるクラスなどにありましたが、それが問題になる可能性があるため、大幅な書き直しを行いました。一部のsqlcommandsは別の場所に書き込まれ、に返されますが、すべてのsqlcommandsは同じメソッド内にあります。主な方法。

現時点での問題は、最初のコマンド(INSERT)が実行されますが、最初のコマンドで作成されたデータベースエントリを参照しようとするため、2番目のコマンドでトランザクションが失敗することです。

また、ネットワーク上のMSDTCが他の問題を引き起こし、アプリケーションとADO.NETでこれを処理する必要があるため、TransactionScopeを使用できません。

編集(いくつかのコード)

トランザクション内の最初の2つのsqlコマンドは次のとおりです。

string connectionString = aSystem.ConnectionString;

    using (SqlConnection linkToDB = new SqlConnection(connectionString))
    {
        linkToDB.Open();
        using (SqlTransaction transaction = linkToDB.BeginTransaction())
        {
            try
            {                            
                //...Case...//

                cCase c = new cCase();
                c.CaseType = cboCaseType.Text;
                c.Occupation = txtOccupation.Text;
                c.DateInstructed = txtDateInst.Text;
                c.Status = "Live";
                SqlCommand sqlSaveCase = c.SaveSqlCom();                               
                sqlSaveCase.Connection = linkToDB;
                sqlSaveCase.Transaction = transaction;
                c.SetCaseNo = sqlSaveCase.ExecuteNonQuery().ToString();

                //...IP Link...//

                string strIPID = cboIPAddress.SelectedValue.ToString();
                SqlCommand sqlNewIPLink = cIPID.NewIPLinkSqlCom(strIPID,c.CaseNo,txtIPRef.Text);
                sqlNewIPLink.Connection = linkToDB;
                sqlNewIPLink.Transaction = transaction;
                sqlNewIPLink.ExecuteNonQuery();                //...fails here...//


                //...an additional 8 sql commands follow...//

問題

sqlSaveCaseコマンドはtblCasesに新しいケースを挿入しますが、2番目のコマンドsqlNewIPLinkが最初のコマンドによって作成されたIDを使用しようとすると、最初のコマンドから新しく作成されたケースが表示されないかのように外部キーエラーが生成されます。

4

4 に答える 4

3

エラーはこの行でした

c.SetCaseNo = sqlSaveCase.ExecuteNonQuery().ToString(); 

INSERTコマンドからIDを取得するには、ExecutreScalar()を使用する必要があります。手がかりは、それが常に1を返していることに最終的に気付いたときに来ました。これは、コマンドが実行されたと言うブール値の「true」であると思います。代わりにコマンドでExecuteScalarを使用すると、後続のSqlCommandsが認識したより意味のあるIDを返し始めたため、ForeginKeyの問題は発生しませんでした。

于 2012-07-28T10:29:18.073 に答える
1

これが問題かどうかはわかりませんが、2番目のSqlCommandでc.SetCaseNoを使用している場所がわかりません。

  //
  // here you are setting c.SetCaseNo
  //
  c.SetCaseNo = sqlSaveCase.ExecuteNonQuery().ToString();

  string strIPID = cboIPAddress.SelectedValue.ToString();

  //
  // but here you're using c.CaseNo
  //
  SqlCommand sqlNewIPLink = cIPID.NewIPLinkSqlCom(strIPID,c.CaseNo,txtIPRef.Text);


  sqlNewIPLink.Connection = linkToDB;
  sqlNewIPLink.Transaction = transaction;
  sqlNewIPLink.ExecuteNonQuery();   
于 2012-07-28T10:28:33.120 に答える
0

TransactionScopeクラスを使用できます。

ここにそれの良い説明があります。

お役に立てれば。

于 2012-07-28T09:10:05.590 に答える
0

あなたの場合、コマンドパターンを使用することをお勧めします。実際、操作を元に戻すことができます。トランザクションは少数の操作に適していますが、10回の操作では、ループで各コマンドを実行し、1つのコマンドが失敗した場合は、コマンドを元に戻すことをお勧めします。これは、ロールバック操作(ここでは10)を実装することを意味します。ここにパターンサンプルのリンクがあります:http://www.dofactory.com/Patterns/PatternCommand.aspx

于 2012-07-28T09:47:50.150 に答える