2016-06-20 18 views
0

同時実行エラーを取得する。これは、私のテーブルです:は、データアダプタでレコードを更新するに

学生StudentId int PK autoincrement,Name varchar(20)

私は最後に追加されたレコードを更新しようとしていたとき、私はエラーをgetingています:

エラーConcurrency violation: the UpdateCommand affected 0 of the expected 1 records.

これは私のコードです:

using (var connection = new SqlConnection("MyConnectionstring")) 
      { 
       connection.Open(); 
       SqlDataAdapter adapter = new SqlDataAdapter(); 
       SqlCommandBuilder builder = new SqlCommandBuilder(adapter); 

       adapter.SelectCommand = new SqlCommand("select * from Student", connection); 


       DataTable dt = new DataTable(); 
       adapter.Fill(dt); 

       DataRow row = dt.NewRow(); 
       row["Name"] = "Abc"; 
       dt.Rows.Add(row); 
       var addedRecords = dt.GetChanges(DataRowState.Added); 
       adapter.Update(dt); 
       dt.AcceptChanges(); 
       DataRow lastRow = dt.Rows[dt.Rows.Count - 1]; 

       row["Name"] = "Pqr"; 
       adapter.Update(dt); //Error Here 
       connection.Close(); 
      } 

誰でもこの問題が発生している理由と、この問題の回避策を教えてください。

+0

あなたは二度同じ行を変更しました。それは意図的でしたか?または、最後の行を変更するつもりでしたか? –

+1

私はあなたがlastrowを変更したいと思うなら、int lastrow = dt.Rows.Count - 1;行[lastrow] ["Name"] = "pqr"; –

+0

@PanagiotisKanavos:最初にレコードを追加したいのですが、最近追加されたレコードを更新したいのですが、実際には私がこれをやっている理由をrowstateのプロセスを理解しようとしています –

答えて

1

Generating Commands with CommandBuilders MSDNトピックで説明したように、コマンドビルダーによって生成された自動コマンドが挿入されたレコードのIDフィールドを取得していない:

Retrieving Identity or Autonumber Valuesトピックを見てみると

You might want to map output parameters back to the updated row of a DataSet. One common task would be retrieving the value of an automatically generated identity field or time stamp from the data source. The DbCommandBuilder will not map output parameters to columns in an updated row by default. In this instance you must specify your command explicitly.

、それは基本的にはあなたが必要なことが判明します手動で挿入コマンドを生成します。ここで

は(コード内のコメントを参照してください)あなたのテーブルのためにそれを行うことができる方法である。

using (var connection = new SqlConnection("MyConnectionstring")) 
{ 
    connection.Open(); 

    // Create data adapter with the specified SelectCommand 
    var adapter = new SqlDataAdapter("select * from Student", connection); 

    // Build InsertCommand  
    var insertCommand = new SqlCommand(
     "insert into Student (Name) values (@Name) SET @Id = SCOPE_IDENTITY()", 
     connection); 
    insertCommand.Parameters.Add("@Name", SqlDbType.VarChar, 20, "Name"); 
    var parameter = insertCommand.Parameters.Add("@Id", SqlDbType.Int, 0, "StudentId"); 
    parameter.Direction = ParameterDirection.Output; 
    insertCommand.UpdatedRowSource = UpdateRowSource.OutputParameters; 
    adapter.InsertCommand = insertCommand; 

    // Auto build outher commands 
    var builder = new SqlCommandBuilder(adapter); 

    // Read the data 
    var dt = new DataTable(); 
    adapter.Fill(dt); 

    // Insert a new record 
    var row = dt.NewRow(); 
    row["Name"] = "Abc"; 
    dt.Rows.Add(row); 

    adapter.Update(dt); 

    // Update the just inserted record 
    row["Name"] = "Pqr"; 
    adapter.Update(dt); 

    connection.Close(); 
} 
+0

これは、私の最後のレコードの更新の間にそれが理由です。netは最後のレコードのIDを見つけることができません。そのレコードはデータベースでコミットされていますが、@Amyによって指摘されているデータテーブルにはまだ存在しません。 –

+1

はい。これは、データベースによって自動的に生成されるID列の特定の問題です。挿入(新規追加)と生成された値を何らかの形で読み戻さなければならない場合のみ発生します(テーブルレコードを対応するデータベースレコードと照合するためには、更新、削除などが実際にそのIDを必要とするためです)。 –

+1

おそらく私はできますが、別の質問を記入してください。私(または他の誰か)が答えることができます。 –

1

最初の更新を実行すると、その行がデータベースに書き込まれ、AUTOINCREMENTごとに1次キーが取得されます。ただし、DataTable内の行には、変更されたIDは反映されません。したがって、2回目の更新を実行しようとすると、更新しようとしている行が見つかりません(データテーブルのIDがデータベースのIDと一致しません)。したがって、同時実行エラーが発生します。

IDをDataTableに登録するには、2回目の更新を行う前にDataTableの内容を更新する必要があります。

DataTable、コール更新するには:詳細については

adapter.Fill() 

を、Merging DataSet Contentsをお読みください。

関連する問題