Статьи

Массовая вставка данных с использованием C # DataTable и функции SQL Server OpenXML


В этом посте я собираюсь показать, как вы можете вставить объемные данные, используя DataTable из C # и функцию OpenXML, доступную в Sql Server.

Я получил требование, что «Чтение данных из файла Excel, а затем после проверки данных

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

Чтобы выполнить задачу, я сделал следующим образом

OpenXML.

Я создал процедуру, которая использует функцию OpenXML сервера sql, которая позволяет вставлять несколько записей одновременно. OpenXML требует XML-строку записи для вставки данных в базу данных.

ALTER PROCEDURE [dbo].[Ins_Employee]    
(    @XmlString text    )    
AS    
BEGIN    
 SET NOCOUNT ON    
 BEGIN TRANSACTION    
 Begin Try    

  DECLARE @XMLDocPointer INT    
  EXEC sp_xml_preparedocument @XMLDocPointer OUTPUT, @XmlString    

   INSERT INTO Employee
   (Name, Email, PhoneNo)    
   SELECT Name,Email,PhoneNo   
   FROM OPENXML(@XMLDocPointer,'/ROOT/DATA',2)    
   WITH  (Name VARCHAR(50),-- '@Name',     
         Email VARCHAR(50),-- '@Email',     
         PhoneNo VARCHAR(50) --'@PhoneNo')     

   EXEC sp_xml_removedocument @XMLDocPointer    
   COMMIT TRANSACTION    
   Return 0;     
 End Try    
 Begin Catch    
   ROLLBACK TRANSACTION    
 End Catch    
END 

Как вы видите выше, процедура OpenXML использует xmlDocument в качестве входных данных, которые создаются системой, определяют процедуру sp_xml_preparedocument, которая принимает xmlString в качестве входных данных и возвращает XmlDocument.

После того, как OpenXML выполнит задачу вставки sp_xml_removedocument, системная процедура должна удалить этот элемент.

Все записи вставляются в один раз с помощью функции OpenXML, так как я использовал транзакцию, если вставка одной записи не удалась, все вставленные записи получают откат.

Следующая строка кода, используемого для выполнения кода, т.е. хранимой процедуры.

Как вы видите, я передаю Element centric xml в процедуру.

Exec Ins_Employee
 '
  
    pranay
    pranayamr@gmail.com
    99007007
  
 '

Примечание.

Если вы передаете XML-строку как атрибут, ориентированный на нее, как в процедуре, вам нужно определить переменную, чтобы оператор выбора в процедуре был

SELECT Name,Email,PhoneNo   
   FROM OPENXML(@XMLDocPointer,'/ROOT/DATA',2)    
   WITH  (Name VARCHAR(50) '@Name',     
         Email VARCHAR(50) '@Email',     
         PhoneNo VARCHAR(50) '@PhoneNo')
Exec Ins_Employee
  '     
       
  '

Теперь, после завершения работы с базой данных, кодовая часть приложения выглядит следующим образом.

Загруженный файл Excel, который содержит данные сотрудника

Уровень представления

Следующая функция в уровне представления считывает данные из файла excel, который загружается на сервер.

private void ReadAndInsertExcelData()
{
     int i;
     bool blValid = true;
     OleDbCommand ocmd;
     OleDbDataAdapter oda;
     DataTable dtDetails;
     DataSet dsDetails;

     OleDbConnection oconn = new OleDbConnection     
          (@"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + 
               Server.MapPath("~/Upload/MonthlyActual.xls") + ";Extended 
               Properties='Excel 8.0;HDR=YES;IMEX=1'");
     try
     {
          ocmd = new OleDbCommand("select * from [Sheet1$]", oconn);
          oda = new OleDbDataAdapter(ocmd);
          dsDetails = new DataSet();
          oda.Fill(dsDetails, "DATA");
          dtDetails = dsDetails.Tables[0];
          dsDetails.DataSetName = "ROOT";
          i = 0;

          DataRow[] drLst = dtDetails.Select("(Name is null) or (Email is 
                              null) or (PhoneNo is null)");
          if (drLst.Count() > 0)
               blValid = false;
          if (blValid)
          {
               XMLController xMLController = new XMLController();
               xMLController.Ins(BaseLineType, dtDetails);
          }
     }
     catch 
     {
          lblMsg.Text = ex.Message;
          lblMsg.ForeColor = System.Drawing.Color.Red;
     }
     finally
     {
          lblMsg.Text = "Data Inserted Sucessfully";
          oda = null;
          dtDetails = null;
          dsDetails = null;
     }
}

Приведенная ниже функция бизнес-уровня принимает DataTable в качестве входных данных и генерирует XML-строку. Как вы видите ниже, я использовал StringWriter, который использует объект StringBuilder, а DataTable использует StringWriter и записывает XML-строку в объект StringBuilder.

public int Ins(DataTable pImportTable)
{
     int IsSuccess = -100;
     try
     {
          StringBuilder sbXMLString = new StringBuilder();
          System.IO.StringWriter sw = new System.IO.StringWriter
                                                  (sbXMLString);
          pImportTable.WriteXml(sw);

          DALXML dALManualCost = new DALXML();
          dALManualCost.Ins(sbXMLString.ToString());
          IsSuccess = dALManualCost.IsSuccess;
     }
     catch
     {
          throw;
     }
     return IsSuccess;
}

Примечание. Вышеуказанный метод создает XML-строку, ориентированную на элемент.

Теперь, если вы хотите записать xml-файл, ориентированный на атрибуты, вам просто нужно заменить строку datatable.WriteXml на приведенный ниже код цикла, также вам не нужно использовать объект StringWriter.

sbXMLString.Append("");
          for (int i = 0; i < pImportTable.Rows.Count; i++)
          {
            sbXMLString.Append("<DATA ");
            sbXMLString.Append("Name='" + 
                         pImportTable.Rows[i][0].ToString().Trim() + "' ");
            sbXMLString.Append("Email='" + pImportTable.Rows
                         [i][1].ToString().Trim() + "' ");
            sbXMLString.Append("PhoneNo='" + 
                         pImportTable.Rows[i][2].ToString().Trim() + "' ");
            
            sbXMLString.Append(" />");
 
          }
          sbXMLString.Append("");

DataLayer 

Теперь этот слой вызывает хранимую процедуру, которая передает xmlstring employee в базу данных. Возвращаемый параметр скажет, что его вставка прошла успешно или нет.

public void Ins(string pXMLString)
{
     try
     {
          Database db = CommonHelper.GetDataBaseInstance();
          DbCommand cmdXML = db.GetStoredProcCommand
                         (SP_INSERT_STAGINGMANUALCOSTMONTHLY);

          db.AddInParameter(cmdXML, "XmlString", DbType.String, 
                                                       pXMLString);
          db.AddParameter(cmdXML, "ret", DbType.Int32,                     
          ParameterDirection.ReturnValue, "", DataRowVersion.Current, 
                                                            IsSuccess);

          db.ExecuteNonQuery(cmdXML);
          IsSuccess = Convert.ToInt32(db.GetParameterValue(cmdXML, "ret"));
     }
     catch
     {
          IsSuccess = -100;
          throw;
     }
}

Примечание: это один метод, который я нашел полезным для ввода большого количества данных в базе данных в одной транзакции. Есть и другие доступные, которые могут быть более эффективными, чем эта.