簡體   English   中英

使用用戶定義的表類型 - 操作數類型沖突從 excel 到 SQL 的 MVC 300K 行數據表

[英]MVC 300K row data table from excel into SQL using User-defined Table Types - Operand type clash

我想通過 MVC 和用戶定義的表類型將 300K + 行從 excel(熱監控數據)導入 MsSQL DB。

我選擇使用表類型和存儲過程,因為我不想循環瀏覽數據並創建動態 SQL 來上傳 300K 記錄,因為這需要一段時間來處理(嘗試過。)。

我正在使用的過程是:

  • 使用 JSON 將數據從 MVC 頁面導入 controller
  • 將 InputStream 傳遞給 GetDataFromCSVFile 函數
  • 創建 DataTable 並使用 stream 填充
  • 使用數據類型和表創建新的 SqlParameter
  • 然后我使用存儲過程將數據表傳遞給 msSql 服務器。

完整代碼。

Public Async Function DataImport(ByVal DataImports As HttpPostedFileBase) As Task(Of ActionResult)

            If DataImports Is Nothing Then Return Json(New With {Key .Status = 0, Key .Message = "No File Selected"})

                
             Try
                Dim fileData = GetDataFromCSVFile(DataImports.InputStream)
                Dim dtManualHeatData = fileData.ToArray()

                Dim table As DataTable = New DataTable()
                table.Columns.Add("ManualHeatDataId", GetType(String))
                table.Columns.Add("DateAndTime", GetType(Date))
                table.Columns.Add("Pulse", GetType(Integer))

                For Each Line As Object In dtManualHeatData
                    Dim row As DataRow = table.NewRow()
                    row("ManualHeatDataId") = Line.ManualHeatDataId
                    row("DateAndTime") = Line.DateAndTime
                    row("Pulse") = Line.Pulse
                    table.Rows.Add(row)
                Next
                Dim tblManualHeatData = New SqlParameter("myManualHeatDatas", SqlDbType.Structured) With {.TypeName = "dbo.ManualHeatDatasType",
                                                                                                            .Value = table
                                                                                                        }
                Dim SQL As String = "EXEC dbo.ImportManualHeatData @myManualHeatDatas"
                Await db.Database.ExecuteSqlCommandAsync(SQL, tblManualHeatData)
                Return Json(New With {Key .Status = 1, Key .Message = "File Imported Successfully "})
            Catch ex As Exception
                Return Json(New With {Key .Status = 0, Key .Message = ex.Message})
            End Try
End Function
Private Function GetDataFromCSVFile(ByVal stream As Stream) As List(Of ManualHeatData)
        Dim ManualHeatList = New List(Of ManualHeatData)()
        Try
            Using reader = ExcelReaderFactory.CreateReader(stream)
                Dim dataset = reader.AsDataSet(New ExcelDataSetConfiguration() With {
                                    .ConfigureDataTable = Function(__) New ExcelDataTableConfiguration() With {
                                    .UseHeaderRow = True,
                                    .ReadHeaderRow = Function(rowReader)
                                                         rowReader.Read()
                                                         rowReader.Read()
                                                         rowReader.Read()
                                                         rowReader.Read()
                                                         rowReader.Read()
                                                         rowReader.Read()
                                                     End Function}})

                If dataset.Tables.Count > 0 Then
                    Dim dataTable = dataset.Tables(0)
                    Dim Count As Long = 0
                    For Each objDataRow As DataRow In dataTable.Rows
                        Count = +1
                        If objDataRow.ItemArray.All(Function(x) String.IsNullOrEmpty(x?.ToString())) Then Continue For
                        ManualHeatList.Add(New ManualHeatData() With {
                            .ManualHeatDataId = Count,
                            .DateAndTime = objDataRow("Date").ToString(),
                            .Pulse = objDataRow("Pulses (Pulses)").ToString()
                        })
                    Next
                End If
            End Using

        Catch Ex As Exception
            Throw
        End Try

        Return ManualHeatList
End Function

上面的整個過程直到 Await db.Database.ExecuteSqlCommandAsync 大約需要 15 秒,這對我的需求來說很好。 問題是運行 db.Database.ExecuteSqlCommandAsync 時出現以下錯誤。

操作數類型沖突:ManualHeatDatasType 與 nvarchar 不兼容

我已經能夠將 go 插入 SQL 服務器並查看 SQL 已由上述代碼傳遞給它但未使用事件記錄器。 當我查看這個 SQL 語句時,它只有 3711 行長,當我使用 SSMS 激發它時,它會正確地將行添加到所需的表中。 下面是 SQL 語句的示例,如在事件記錄器中看到但未執行。

declare @p3 dbo.ManualHeatDatasType
insert into @p3 values(N'1','2020-10-14 12:31:15',0)
insert into @p3 values(N'1','2020-10-14 12:31:25',1)
insert into @p3 values(N'1','2020-10-14 12:31:35',0)
..loads more rows!...
insert into @p3 values(N'1','2020-10-14 22:48:45',0)
insert into @p3 values(N'1','2020-10-14 22:48:55',0)
insert into @p3 values(N'1','2020-10-14 22:49:05',0)
insert into @p3 values(N'1','2020-10-14 22:49:15',0)
insert into @p3 values(N'1','2020-10-14 22:49:25',0)
insert into @p3 values(N'1','2020-10-14 22:49:35',0)

exec sp_executesql N'EXEC dbo.ImportManualHeatData @myManualHeatDatas',N'@myManualHeatDatas [dbo].[ManualHeatDatasType] READONLY',@myManualHeatDatas=@p3

如果我多次重復測試,它總是在傳遞給 SQL 的 3711 行處停止並且不運行。 所以我認為這個問題與數據表/流中 3711 或 22:49:35 之后的數據有關。

但是圍繞這一點的所有數據都是干凈的,並且與之前的數據完全相同。

如果有人對哪里出了問題有任何指示或反饋,請告訴我。 干杯,理查德。

好的,找到了解決方案!

而不是使用存儲過程,表類型並將數據表映射到我找到的類型SqlBulkCopy !!!

After creating the table in the original question above I am able to use the SqlBulkCopy as below to push the whole datatable into the SQL server and the whole process of reading and importing into SQL for 300k rows from excel takes around 5 seconds!! 腦洞大開!!

            Using dbcontext As ApplicationDbContext = New ApplicationDbContext()
                Dim sqlCon As SqlConnection = New SqlConnection(DbContext.Database.Connection.ConnectionString)
                sqlCon.Open()
                Using bulkCopy As SqlBulkCopy = New SqlBulkCopy(sqlCon)
                    bulkCopy.DestinationTableName = Data_Base + ".dbo.ManualHeatDatas"
                    Try
                        bulkCopy.WriteToServer(table)
                    Catch ex As Exception
                        Console.WriteLine(ex.Message)
                    Finally
                        table.Dispose()
                    End Try
                End Using
            End Using

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM