2016-06-20 6 views
0

данных Это мой стол:Получение ошибки параллельности на обновление записи с адаптером

Студент: StudentId int PK autoincrement,Name varchar(20)

Когда я пытаюсь обновить последние добавленные записи об ошибке, то я адресности:

Ошибка: 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; row [lastrow] ["Name"] = "pqr"; –

+0

@PanagiotisKanavos: сначала я хочу добавить запись, а затем я хочу обновить эту недавно добавленную запись, и на самом деле я пытаюсь понять процесс rowstate, поэтому я делаю это –

ответ

1

Как описано в Generating Commands with CommandBuilders MSDN теме, автоматические команды, сгенерированный командой строителей не получить поля идентификаторов для вставленных записей:

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.

Глядя на Retrieving Identity or Autonumber Values тему, получается, что в основном вам нужно для генерации команды вставки вручную.

Вот как вы можете сделать это для вашей таблицы (см комментарии в коде):

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

Так вот почему во время обновления моих последних записей ado.net не может найти идентификатор последней записи, потому что эта запись заносится в базу данных, но все еще не существует в datatable, как указано @Amy ?? –

+1

Да. Это конкретная проблема с столбцами идентификаторов, которые автоматически генерируются базой данных. Это происходит только тогда, когда вставить (добавить новое) и сгенерированное значение должно как-то быть прочитано (поскольку обновление, удаление и т. Д. Действительно нуждается в этом id, чтобы соответствовать записи таблицы с соответствующей записью базы данных). –

+1

Скорее всего, я могу, но, пожалуйста, заполните другой вопрос, чтобы я (или кто-то еще) мог ответить на него. –

1

Когда вы делаете первое обновление, строка записывается в базу данных и получает первичный ключ для AUTOINCREMENT. Однако строка внутри DataTable не отражает измененный идентификатор. Поэтому, когда вы пытаетесь выполнить второе обновление, он не может найти строку, которую вы планируете обновлять (идентификатор в таблице данных не соответствует идентификатору в базе данных). Следовательно, вы получаете ошибку параллелизма.

Именно поэтому, чтобы получить идентификатор в DataTable, вам необходимо обновить содержимое DataTable перед выполнением второго обновления.

Чтобы обновить DataTable, вызов:

adapter.Fill() 

Для получения более подробной информации читайте Merging DataSet Contents.

 Смежные вопросы

  • Нет связанных вопросов^_^