2009-05-08 1 views
3

У меня есть приложение winforms с двумя DataGridViews, отображающими отношения мастер-детали из моих таблиц Person и Address. Таблица Person имеет поле PersonID, которое является автоматически увеличивающим первичный ключ. Адрес имеет поле PersonID, которое является FK.DataRelation Insert и ForeignKey

Я заполняю DataTables DataAdapter и устанавливаю AutoIncrement столбца Person.PersonID = true и AutoIncrementStep = -1. Я могу вставлять записи в DataTable Person из DataGridView. В столбце PersonID отображаются уникальные отрицательные значения для PersonID. Я обновляю базу данных, вызывая DataAdapter.Update (PersonTable), а отрицательные персональные идентификаторы автоматически преобразуются в положительные уникальные значения SQL Server.

Вот протирать. Адрес DataGridView показывает таблицу адресов, которая имеет DataRelation для Person по PersonID. Записи «Вставленные лица» имеют временный отрицательный идентификатор PersonID. Теперь я могу вставлять записи в адрес через DataGridView и Address.PersonID устанавливается отрицательное значение из сопоставления DataRelation. Я вызываю Adapter.Update (AddressTable), а отрицательные персонажи попадают в таблицу Address, нарушая связь.

Как вы, ребята, обрабатываете первичные/внешние ключи с помощью DataTables и master-detail DataGridViews?

Спасибо! Стив

EDIT:

После еще Googling, я обнаружил, что SqlDataAdapter.RowUpdated событие дает мне то, что мне нужно. Я создаю новую команду для запроса последнего вставленного идентификатора с помощью @@ IDENTITY. Это работает очень хорошо. DataRelation обновляет поле Address.PersonID для меня, поэтому сначала необходимо обновить таблицу Person, а затем обновить таблицу Address. Все новые записи правильно вставляются с правильными идентификаторами на месте!

  Adapter = new SqlDataAdapter(cmd); 
      Adapter.RowUpdated += (s, e) => 
      { 
       if (e.StatementType != StatementType.Insert) return; 
       //set the id for the inserted record 
       SqlCommand c = e.Command.Connection.CreateCommand(); 
       c.CommandText = "select @@IDENTITY id"; 
       e.Row[0] = Convert.ToInt32(c.ExecuteScalar()); 
      }; 
      Adapter.Fill(this); 
      SqlCommandBuilder sb = new SqlCommandBuilder(Adapter); 
      sb.GetDeleteCommand(); 
      sb.GetUpdateCommand(); 
      sb.GetInsertCommand(); 
      this.Columns[0].AutoIncrement = true; 
      this.Columns[0].AutoIncrementSeed = -1; 
      this.Columns[0].AutoIncrementStep = -1;  

ответ

1

Чтобы добавить комментарий, вам необходимо двойное щелчок мышью в конструкторе набора данных и выберите Cascade Updates. Когда ваш реальный SQL-сервер генерирует значения PK для вашей таблицы Person, он автоматически устанавливает значения внешнего ключа в таблице адресов.

Вам не нужно делать какие-либо события, связанные с RowUpdated. Он встроен в функциональность набора данных.

1

У меня была аналогичная проблема, но мое решение было немного иным.

@Noel Kennedy: Ваше решение не работает с SQL Server 2005 CE, поскольку оно не поддерживает несколько операторов, а TableAdapter не генерирует код обновления, необходимый для обновления столбцов автоинкремента в родительской таблице.

ПРИМЕЧАНИЕ. Вам необходимо обновить Cascade в отношении, чтобы дочерние таблицы обновлялись.

Я также добавляю метод в свой TableAdapter, который достаточно общий, чтобы просто копировать/вставлять все родительские TableAdapters. Единственное, что я меняю, это тип и индекс строки идентификатора (при необходимости). Я также добавляю запрос к TableAdapter под названием GetIdentity(). Вы можете добавить его в TableAdapter в дизайнере набора данных, добавив скалярный запрос с sql = "SELECT @@ IDENTITY;"

Теперь пользовательская функция:

public int InsertAndRefresh(System.Data.DataTable dataTable) 
{ 
    int updated = 0; 

    System.Data.DataRow[] updatedRows = dataTable.Select("", "", System.Data.DataViewRowState.Added); 

    bool closed = (this.Connection.State == System.Data.ConnectionState.Closed); 
    if (closed) 
     this.Connection.Open(); 

    foreach (System.Data.DataRow row in updatedRows) 
    { 
     updated+=this.Adapter.Update(new global::System.Data.DataRow[] { row }); 
     decimal identity = (decimal)this.GetIdentity(); 
     row[0] = System.Decimal.ToInt64(identity); 
     row.AcceptChanges(); 
    } 
    if (closed) 
     this.Connection.Close(); 

    return updated; 
} 

Вы хотите назвать это на родителе первым. Затем сделайте все как обычно (обновите родителя, а затем детей).

Приветствия!

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

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