为啥这个 DataAdapter 不会将行插入到数据库中?

Posted

技术标签:

【中文标题】为啥这个 DataAdapter 不会将行插入到数据库中?【英文标题】:Why won't this DataAdapter insert rows into the database?为什么这个 DataAdapter 不会将行插入到数据库中? 【发布时间】:2017-09-21 14:40:42 【问题描述】:

所以我有一种情况,我使用 SqlDataAdapter 将行插入到 SQL Server 2014 数据库中的表中。

数据来源是 Excel 电子表格。

当使用几个 For 循环和 .Columns.Add 和 .Rows.Add 填充 DataTable 对象以从 Excel 工作表复制数据时,插入工作正常。这个工作代码我没有在这里包含。

但是,我正在重构代码以使用 OleDbDataReader。这是我的功能:

Private Function FillDataTable(path As String, name As String) As DataTable
        Dim fullpath As String = path
        Dim wsname As String = name
        Dim dt = New DataTable()
        Try
            Dim connectionstring As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" & fullpath & "';Extended Properties= 'Excel 8.0;HDR=Yes;IMEX=1'"
            Dim commandstring As String = "Select * From " & wsname
            Using con As New OleDbConnection(connectionstring)
                Using cmd As New OleDbCommand(commandstring, con)
                    con.Open()
                    Using dr As OleDbDataReader = cmd.ExecuteReader()
                        With dt
                            For Each c In aryFieldList
                                .Columns.Add(c.FieldName, ConvertType(c.DataType))
                            Next

                            .Columns.Add("SubmID")
                            .Columns("SubmID").DefaultValue = 0

                            .Columns.Add("S_ORDER")
                            .Columns("S_ORDER").DefaultValue = 0

                            .Columns.Add("C_ORDER")
                            .Columns("C_ORDER").DefaultValue = 0
                        End With
                        dt.Load(dr)
                    End Using
                End Using
            End Using

        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
        Return dt

    End Function

当我调试时,从函数返回的 DataTable 在集合中有数据,否则看起来与以前版本代码中的 DataTable 相同。这是更新数据库的代码。对于这两种情况,此代码不变

    Dim dt = New DataTable()
    dt = FillDataTable(fullpath, wsname)

Using cn = New SqlConnection(ConfigurationManager.ConnectionStrings("Connection").ConnectionString)
    cn.Open()
    Using adp = New SqlDataAdapter()
        Dim sb As New StringBuilder

        [...StringBuilder code to build the Insert command here...]

        Dim cmd As New SqlCommand(sb.ToString, cn)

        With adp
            .InsertCommand = cmd
            .InsertCommand.Parameters.Add("SubmID", SqlDbType.Int, 1, "SubmID")
            .InsertCommand.Parameters.Add("S_ORDER", SqlDbType.Int, 1, "S_ORDER")
            .InsertCommand.Parameters.Add("C_ORDER", SqlDbType.Int, 1, "C_ORDER")

            For Each p In aryFieldList
                If p.Excluded = False Then
                    .InsertCommand.Parameters.Add(p.FieldName, p.DataType, p.Length, p.FieldName)
                End If
            Next
                adp.Update(dt)

        End With 'adp
    End Using 'adp
End Using 'cn

永远不会抛出异常。调试 adp.Update(dt) 行没有延迟,就好像根本没有执行查询一样。这是我注意到的添加的行/列 DT 和填充 OleDB 的 DT 之间的唯一区别——成功插入数据时会有轻微的延迟时间。

我是否缺少DataTable 的某种基本功能或属性,或者可能是在加载期间继承或创建的属性?是我没有想到的其他事情吗?当源是手动创建的DataTable 而不是由OleDbReader 填充的DataTable 时,为什么我的SqlDataAdapter 将数据插入数据库?

【问题讨论】:

A DataTable 跟踪每一行的RowState,因此手动添加循环有效,因为它们都是Added。如果您从其他来源加载,则不会添加/新建它们。 (仍在涉水通过该代码) 您是否尝试过使用 cmd.ExecuteNonQuery 而不是 adp.update? 如果您使用数据适配器填充表格,您可以使用myDA.AcceptChangesDuringFill = False 这样行状态标志不会被清除 @Plutonix 是否可以在 .Load 之后或期间更改 RowState 以便添加它们? @Benno 仅供参考,我们实际上最终使用了 sqlbulkcopy 而不是这两种方法,因为我们在导入之前对所有 Excel 列进行数据输入、验证和清理,因此我们可以简单地执行 ColumnMapping 操作并插入100,000 行用时不到 5 秒。对于相同的插入,适配器操作大约需要 30 分钟。我们还希望避免在 SQL 中创建表类型来执行我们的插入操作。谢谢你的建议! 【参考方案1】:

每个DataTable 跟踪其行的RowState,因此在循环中手动添加数据是可行的,因为它们都是Added(它与手动创建DataTable 无关 - 它的)。当您从 Excel 等其他来源加载时,它们不会添加/新。

如果您使用DataAdapter 填充表格,您可以告诉它RowState 设置为未更改。这对于将数据从一个数据存储迁移到另一个非常有用:

myDA.AcceptChangesDuringFill = False
...
rows = myDA.Fill(xlDT)

【讨论】:

【参考方案2】:

我有同样的问题,解决方案很简单,一旦你看到它......我在 Visual Studio 中有我的数据库,它的属性“复制到输出目录”设置为“始终复制”,而不是“不要复制”。所以每次我运行我的代码时,数据库都会被删除!

解决方案: - 修改您的连接字符串,使其直接指向您的数据库 - 将您的数据库属性更改为“请勿复制”

【讨论】:

以上是关于为啥这个 DataAdapter 不会将行插入到数据库中?的主要内容,如果未能解决你的问题,请参考以下文章

将行插入 QSqlTableModel

为啥 DataAdapter.Update 啥也不更新?

为啥当我调用 DataAdapter.Update() 时,此 C# 代码会生成语法错误?

从c#按顺序将行插入Access Table

为啥这个 PHP 脚本不会在 MySQL 数据库中插入表单数据?

将行插入到只有一个主键字段的表中