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

Я новичок в ado.net и в настоящее время работаю над вставкой записей с данными в таблицы базы данных.

У меня есть 1 файл Excel, содержащий некоторые данные, и из этого файла Excel я создаю набор данных, который содержит множество таблиц данных.

В этом наборе данных у меня есть 2 таблицы данных в виде этого:

Datatable 0 с записями: Категория

ParentCategory Description
  Electronics   jhdkhsd
  Sports        kjshfhs

Дата 1 с записями: Подкатегория

Subcategory ParentCategory  Description
  Mobile       Electronics   weprwp
  Tv           Electronics   sdflskd
  Balls        Sports        kjshdfkjh
  Shoes        Sports        uytuyt

Теперь мои таблицы базы данных выглядят так:

Category:Id,Name,parentid

Итак, в основном я пытаюсь вставить все эти данные datatables, которые являются категориями datatable и SubCategory datatable, в мою таблицу базы данных, которая является категорией, но когда я пытаюсь вставить получение ошибки:

Ошибка: параметризованный запрос '(@Id int output, @ ParentCategory nvarchar (50)) вставить в категорию' ожидает параметр '@ParentCategory', который не был предоставлен.

Это мой код на данный момент:

 var dsFinal = new DataSet();

    //Some code to read Excel sheets and data from Excel and create datatables and records with it.


    //code to insert records
     using (SqlConnection connection = new SqlConnection(""))
     {
       SqlDataAdapter adapter = new SqlDataAdapter();
       var insertCommand = new SqlCommand("insert into Category (Name) values (@ParentCategory) SET @Id = SCOPE_IDENTITY()", connection);
      var parameter = insertCommand.Parameters.Add("@Id", SqlDbType.Int, 0, "Id");
      insertCommand.Parameters.Add("@ParentCategory", SqlDbType.NVarChar, 50, "Name");
      parameter.Direction = ParameterDirection.Output;
     insertCommand.UpdatedRowSource = UpdateRowSource.OutputParameters;
     adapter.InsertCommand = insertCommand;
    adapter.Update(dsFinal .Tables[0]);
   }

Здесь у меня есть свойство состояния rowstate строк с данными для всех категорий, которое нужно добавить, поэтому я напрямую пытаюсь вставить все записи категории.

Должен ли я переходить к отдельным записям и вставлять их? Поскольку у меня огромное количество, например, тысячи категорий вместе с их подкатегориями, и это замедлит мою систему.


person Learning-Overthinker-Confused    schedule 22.06.2016    source источник
comment
Ado ожидает, что параметры в SQL будут в том же порядке, в котором они добавляются в команду. ADO не очень умен и использует индексацию для параметров и не понимает строковых имен параметров.   -  person jdweng    schedule 22.06.2016
comment
@jdweng: но я выполнил этот приказ. Подскажите, пожалуйста, где я сделал ошибку?   -  person Learning-Overthinker-Confused    schedule 22.06.2016
comment
@Jdweng имел в виду, что вы должны обменять строки кода, содержащие Add("@Id" и Add("@ParentCategory")   -  person Ivan Stoev    schedule 22.06.2016
comment
@Ivan Stoev, но Id - это автоинкремент в моей таблице базы данных, а ParentCategory - это то, что я хотел вставить в свое поле Name моего поля базы данных, когда вы смотрите на мой пример вывода, в котором ParentCategory содержит электронные, спортивные, и это то, что я хочу в моем Поле имени моей таблицы базы данных   -  person Learning-Overthinker-Confused    schedule 22.06.2016
comment
@Learning Переместите строку var parameter = insertCommand.Parameters.Add("@Id", SqlDbType.Int, 0, "Id"); после строки insertCommand.Parameters.Add("@ParentCategory", SqlDbType.NVarChar, 50, "Name");   -  person Ivan Stoev    schedule 22.06.2016
comment
@IvanStoev: Извините, я только что попробовал, но он не работает и выдает ту же ошибку, что и в вопросе.   -  person Learning-Overthinker-Confused    schedule 23.06.2016
comment
@jdwengИзвините, я пробовал то, что вы сказали в своем комментарии, но это не сработало, и я получил ту же ошибку, что и в вопросе   -  person Learning-Overthinker-Confused    schedule 23.06.2016
comment
Я не вижу, как здесь одна и та же команда Получение ошибки параллелизма при обновлении записи с адаптером данных работает, а это нет. Единственная разница - это имя таблицы и имя параметра, которое не должно быть существенным. Поскольку у меня нет вашего окружения, я больше ничего не могу сделать.   -  person Ivan Stoev    schedule 23.06.2016
comment
Позвольте нам продолжить это обсуждение в чате.   -  person Learning-Overthinker-Confused    schedule 23.06.2016
comment
@IvanStoev: Вот как я решил ошибку, заданную в этом вопросе. См., Например, этот вопрос: stackoverflow.com/questions/37986204 /   -  person Learning-Overthinker-Confused    schedule 23.06.2016


Ответы (1)


Используйте следующий фрагмент кода.

  • Вам необходимо указать точку с запятой между операторами INSETRT и SCOPE_IDENTITY в команде SQL для вставки.
  • Кроме того, поскольку ваша базовая таблица содержит столбцы ID, Name, ParentId, вы должны сопоставить все эти столбцы с вашей командой вставки и вставлять только столбцы Name и ParentId, поскольку идентификатор создается автоматически. Столбец ID сопоставляется с выходным параметром, а другие столбцы - с входными параметрами.

Вставьте одну строку в базу данных с помощью DataTable

     using(SqlConnection connection = new SqlConnection("")) {
      SqlDataAdapter adapter = new SqlDataAdapter();
      var insertCommand = new SqlCommand("Insert into Category (Name, ParentId) Values (@name, @parentId); SET @ID = SCOPE_IDENTITY(); ", connection);
      var parameter = insertCommand.Parameters.Add("@name", SqlDbType.NVarChar, 50, "Name");
      insertCommand.Parameters.Add("@parentId", SqlDbType.Int, 0, "ParentId");
      SqlParameter parameter = adapter.InsertCommand.Parameters.Add("@ID",SqlDbType.Int, 0, "ID");
      parameter.Direction = ParameterDirection.Output;
      adapter.insertCommand = insertCommand;
      adapter.insertCommand.UpdatedRowSource = UpdateRowSource.OutputParameters;
      adapter.Update(dsControlSheet.Tables[0]);
    }

Вышеупомянутое должно помочь с сообщением об ошибке, которое вы упомянули в своем сообщении.

Приведенный ниже фрагмент кода поможет вам вставлять строки в пакетном режиме, а не по одной, когда вам нужно вставить много строк в базу данных. Вам нужно указать adpapter.UpdateBatchSize на значение больше 1 для пакетных операторов вставки.

Пакетная вставка строк в базу данных из DataTable

 using (SqlConnection connection = new SqlConnection(""))
 {
   SqlDataAdapter adapter = new SqlDataAdapter();
   var insertCommand = new SqlCommand("Insert into Category (Name, ParentId) Values (@name, @parentId);", connection);
   var parameter = insertCommand.Parameters.Add("@name", SqlDbType.NVarChar, 50, "Name");
   insertCommand.Parameters.Add("@parentId", SqlDbType.Int, 0, "ParentId");
   adapter.insertCommand = insertCommand;
   // When setting UpdateBatchSize to a value other than 1, all the commands 
   // associated with the SqlDataAdapter have to have their UpdatedRowSource 
   // property set to None or OutputParameters. An exception is thrown otherwise.
     insertCommand.UpdatedRowSource = UpdateRowSource.None;
   // Gets or sets the number of rows that are processed in each round-trip to the server.
   // Setting it to 1 disables batch updates, as rows are sent one at a time.
    adapter.UpdateBatchSize = 50;
    adapter.Update(dsControlSheet.Tables[0]);
}

При выполнении пакетных вставок необходимо учитывать несколько моментов.

  1. CommandTimeout команды вставки должен быть достаточно большим, чтобы разрешить пакетную вставку, иначе вы получите исключение тайм-аута. Если вы установите для этого тайм-аута значение 0, то время, разрешенное для вставок, не определено.
  2. При выполнении пакетных вставок вы хотите получить максимальную производительность, иначе ваши вставки могут оказаться слишком медленными. Выполняя пакетные вставки как одну транзакцию, вы достигнете этой повышенной производительности. Без транзакции база данных будет запускать транзакцию для каждого INSERT в пакете, что занимает больше времени. Например, если у вас есть 500 в качестве размера пакета (например, adapter.UpdateBatchSize), то 500 операторов INSERT приведут к 500 транзакциям в базе данных, если к команде вставки не прикреплена транзакция; но если вы присоедините транзакцию к команде вставки, тогда будет только 1 транзакция для всех 500 INSERT, что повысит производительность.

Высокая производительность за счет пакетной вставки в базу данных из DataTable

 using (SqlConnection connection = new SqlConnection(connectionString))
 {
   SqlDataAdapter adapter = new SqlDataAdapter();
   var insertCommand = new SqlCommand("Insert into Category (Name, ParentId) Values (@name, @parentId);", connection);
   var parameter = insertCommand.Parameters.Add("@name", SqlDbType.NVarChar, 50, "Name");
   insertCommand.Parameters.Add("@parentId", SqlDbType.Int, 0, "ParentId");
   adapter.insertCommand = insertCommand;
   // When setting UpdateBatchSize to a value other than 1, all the commands 
   // associated with the SqlDataAdapter have to have their UpdatedRowSource 
   // property set to None or OutputParameters. An exception is thrown otherwise.
     insertCommand.UpdatedRowSource = UpdateRowSource.None;
   // Gets or sets the number of rows that are processed in each round-trip to the server.
   // Setting it to 1 disables batch updates, as rows are sent one at a time.
    adapter.UpdateBatchSize = 50;
    //NOTE: When doing batch updates it's a good idea to fine tune CommandTimeout value
    //since default is 30 seconds. If your batch insert takes more than 30 s (default value)
    //then make sure to increase this value. I am setting this to 90 s
    //but you must decide this based on your situation.
    //Set this to 0 if you are not sure how long your batch inserts will take
    insertCommand.CommandTimeout = 90;

    //HOW TO MAKE BATCH INSERTS FASTER IN PERFORMANCE
    //Perform batch updates in a single transaction to increase batch insert performance
    connection.Open();
    var transaction = connection.BeginTransaction();
    insertCommand.Transaction = transaction;
    try { 
         adapter.Update(dsControlSheet.Tables[0]);
         transaction.Commit();
    }
    catch(Exception e) {

    if(transaction!=null) {
       transaction.Rollback();
     }
     //log exception
   }
   finally {
      connection.Close();
   }
}
person Sunil    schedule 22.06.2016
comment
Но у меня нет родительского элемента в моей 0-й таблице данных, так что нужно ли мне указывать родительский элемент в этом случае? - person Learning-Overthinker-Confused; 23.06.2016
comment
Вы можете опустить его, но если этот столбец в базе данных определен как NOT NULL, вы получите сообщение об ошибке. - person Sunil; 23.06.2016
comment
Я добавил еще один фрагмент кода, который показывает, как максимизировать производительность при вставке в пакетном режиме. - person Sunil; 23.06.2016
comment
Большое вам спасибо, сэр. Еще раз спасибо - person Learning-Overthinker-Confused; 23.06.2016
comment
Пожалуйста. Прочтите комментарии во фрагменте кода, чтобы лучше понять. - person Sunil; 23.06.2016