SQLCommandBuilder - 仅从 DataTable 更新“追加”数据库表

Posted

技术标签:

【中文标题】SQLCommandBuilder - 仅从 DataTable 更新“追加”数据库表【英文标题】:SQLCommandBuilder - UPDATE from DataTable only "Appends" Database Table 【发布时间】:2015-08-28 19:23:50 【问题描述】:

我正在尝试使用SQLCommandBuilder 更新数据库表行和使用以下测试代码的数据表行。一张带有主键列的表和一张数据表以保持简单。

使用以下代码,dbo.Dogs2 表“附加”了数据表行 - 因此将行数加倍,而不是仅仅更新更改的行

如果我在Dim builder As New SqlCommandBuilder(adapter) 之前添加代码table.AcceptChanges(),则数据库表dbo.Dogs2 保持不变。

如果我在adapter.Update(table) 之前添加代码table.AcceptChanges(),则数据库表dbo.Dogs2 保持不变。

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        ' dbo.Dogs2 database table columns are exactly like datatable columns with exception of dog names
         ' only UPDATING the "Name" field (no Inserts or deletes)
         ' orginal dog names "Name" in Dogs2.dbo are Sharpy, Bully, Shep, Charlie, and Yorky
         ' new dog names "Name" in Dogs2.dbo are June, Tucker, Maggie, Charles, and Candy
         ' Dex_Row_Id is the primary key with Identity Increment set to 1

        ' Create a DataTable with five columns.
         '
         Dim table As New DataTable()
         table.Columns.Add("Weight", GetType(Integer))
         table.Columns.Add("Name", GetType(String))
         table.Columns.Add("Breed", GetType(String))
         table.Columns.Add("Size", GetType(Char))
         table.Columns.Add("Date", GetType(DateTime))
         table.Columns.Add("Dex_Row_Id", GetType(Integer))
         '
         ' Add data to the DataTable
         '
         AddDogRow(table, 57, "June", "Shar Pei")
         AddDogRow(table, 130, "Tucker", "Bullmastiff")
         AddDogRow(table, 92, "Maggie", "Anatolian Shepherd Dog")
         AddDogRow(table, 25, "Charles", "Cavalier King Charles Spaniel")
         AddDogRow(table, 7, "Candy", "Yorkshire Terrier")

        ShowResult(table)    'displays datatable correctly    (this is a DevExpress.com Reference/Extension)
         '
         ' Create new SqlConnection, SqlDataAdapter, and builder.
         '
         Dim cnString As String = "<<<SQLConnectionString>>>"
         '
         Using cnSQL1 As New SqlConnection
             cnSQL1.ConnectionString = cnString

            Using adapter = New SqlDataAdapter("SELECT * FROM Dogs2", cnSQL1)

                ShowResult(table)  'displays datatable

                Dim builder As New SqlCommandBuilder(adapter)
                 adapter.UpdateCommand = builder.GetUpdateCommand()
                 builder.RefreshSchema()

                Using New SqlCommandBuilder(adapter)
                     '
                     ' Fill the DataAdapter with the values in the DataTable.
                     '
                     adapter.Fill(table)  

                    ShowResult(table)  'displays datatable + original table data

                    ' Open the connection to the SQL database.
                     '
                     cnSQL1.Open()

                    ' Update the SQL database table with the values.
                     '
                     adapter.Update(table)

                    ' dbo.Dogs2 now has 10 rows  (the 5 rows from the dataset + the original 5 rows)

                End Using

            End Using

        End Using

    End Sub

【问题讨论】:

【参考方案1】:

您使用的适配器不正确。您应该首先从数据库中加载行,然后更新检索到的行,最后调用更新。

 ' REMOVE THE CODE BEFORE THIS '
 ' Create new SqlConnection, SqlDataAdapter, and builder.'

 Dim cnString As String = "<<<SQLConnectionString>>>"
 Dim table = New DataTable() ' Leave it emtpy and without schema'
 Using cnSQL1 As New SqlConnection
    cnSQL1.ConnectionString = cnString
    Using adapter = New SqlDataAdapter("SELECT * FROM Dogs2", cnSQL1)
        Dim builder As New SqlCommandBuilder(adapter)
        adapter.UpdateCommand = builder.GetUpdateCommand()
        ' no need of this -> builder.RefreshSchema()'
        Using New SqlCommandBuilder(adapter)
            adapter.Fill(table)  
            ShowResult(table)  'displays original table data'

            ' no need of this -> cnSQL1.Open()'
            ' NOW YOU COULD CHANGE THE ROWS, FOR EXAMPLE'
            table.Rows(0)("Weight") = 99

            ' Update the SQL database table with the values.'
            adapter.Update(table)
        End Using
    End Using
End Using

当您将现有表传递给适配器的 Fill 方法时,现有记录不会被删除,因此您的表会填充来自数据库和手动创建表的数据(当然适配器为您构建表列。此外,手动添加到表中的行标记为DataRowState.Added,而您的代码修改的行将标记为DataRowState.Changed。此状态有助于更新命令决定对每个执行的操作表中存在的行(当然未更改的行保持初始DataRowState.Unchanged

最后,calling AcceptChanges 并不意味着将更新数据库表上的行。只有 DataRowState 标志被重置为DataRowState.Unchanged

【讨论】:

史蒂夫,感谢您提供的有用信息。我根据您的回答修改了我的测试代码,并且数据库表确实更新了。 在我的实际应用程序中,我通过 VS2013 中的 DevExpress.com 电子表格扩展生成一个 DataTable。因此,对于这种情况,我的数据(数据表)已经可用于更新数据库表。换句话说,我的数据表是在“Dim cnString As String = connectionString”代码行之前填充的。我是否正确假设成功的唯一方法是使用参数? 抱歉,一点都不清楚。如果您的表已经有行而不使用适配器来填充它并且您想要更改它们并将更改写回您需要遍历您的行,检查每行的 DataRowState 并直接应用 UPDATE 命令而不使用适配器 Fill 方法.您可以从构建器获取 UpdateCommand 并使用它填充所需的参数 史蒂夫,我通过 myTableAdapter.FillBy_myQuery(myDataTable) 填充电子表格。我将值添加到空列(在我的例子中是“TestResults”)。使用 DevExpress 的 exporter.Export(),将电子表格范围导出到包含添加的“TestResults”的数据表中。这是我希望用来更新数据库表的数据表。从不添加或删除行 - 仅使用“TestResults”更新数据库表中的现有行。

以上是关于SQLCommandBuilder - 仅从 DataTable 更新“追加”数据库表的主要内容,如果未能解决你的问题,请参考以下文章

使用没有主键的 SQLAdapter 和 SQLCommandBuilder

为啥我们要使用 sqlcommandbuilder?

SqlCommandBuilder类是如何构建T-Sql语句

SqlCommandBuilder的讨论

sqlCommandBuilder 更新未按预期工作

在 ASP.NET 中使用 SqlCommandBuilder