SqlDataAdapter.Fill(DataGridView.DataSource) 复制所有行

Posted

技术标签:

【中文标题】SqlDataAdapter.Fill(DataGridView.DataSource) 复制所有行【英文标题】:SqlDataAdapter.Fill(DataGridView.DataSource) duplicates all rows 【发布时间】:2016-11-16 15:59:24 【问题描述】:

简单的问题:

当我在最初创建第一个数据后第二次调用SqlDataAdapter.Fill(DataGridView.DataSource) 时,它不会更新包含的行。它只是将选择命令返回的所有行添加到我的 DataGridView。

如果我称它为第三、第四(依此类推),它也只会添加返回的行。

我对 .Fill(DataTable) 函数的理解有误吗?如何正确更新已经存在的 DataTable?哪一行代码对此负责?


原来是代码问题;

    DataGridView1.AutoGenerateColumns = False
    Dim sql = "select * from myTable"
    oDtSource = New DataTable
    oAdapter = New SqlDataAdapter
    oCon = sqlCon("serverName\Instance", "myDataBase") ' Returns a SqlConnection
    oCmd = New SqlCommand(sql, oCon)
    oCon.Open()

    oDtSource.Clear()

    oAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey
    oAdapter.SelectCommand = oCmd
    oAdapter.Fill(oDtSource)
    DataGridView1.DataSource = oDtSource

为了提神,我使用oAdapter.Fill(oDtSource) PrimaryKey 在数据库中设置

【问题讨论】:

请展示您如何设置 DataAdapter(我假设您正在尝试刷新数据,否则只需使用新数据表或清除行)。不知道为什么 DV 除了可能缺少代码 - 这是一个不错的问题。 我很确定 Tim Schmelter 让我走上了正确的道路。工作时间现在结束了,所以我明天必须检查一下。再次感谢@Plutonix 带我尝试实际的 .Fill 方法,而不是一遍又一遍地创建新表。 代码已在上面发布。 我会加载架构在数据表上定义PrimaryKey。它可以很好地刷新行,但在添加行时可能会有一个刷新技巧 该命令是什么样的,应该在哪一行发布?在第一次调用oAdapter.Fill(oDtSource) 之后,我尝试使用oDtSource.PrimaryKey = New DataColumn() oDtSource.Columns("myPrimaryKey"),但它似乎对我不起作用。它仍然以添加而不是更新的行结束。 【参考方案1】:

来自MSDN:

您可以在同一个DataTable 上多次使用Fill 方法。如果一个 主键存在,传入的行与匹配的行合并 已经存在。如果不存在主键,传入的行将附加到 数据表

所以要么定义主键,要么先清表。

Dim table = CType(DataGridView.DataSource, DataTable)
table.Clear()
' fill  ...

要手动定义主键,请阅读this。要让它在数据库中定义它们时自动创建,您需要将MissingSchemaAction 设置为AddWithKey

' ...
dataAdapter.MissingSchemaAction =  MissingSchemaAction.AddWithKey
' fill ...

【讨论】:

好东西,应该马上看MSDN。我的错。找不到设置主键的命令。你能帮我解决这个问题吗? @Luke: msdn.microsoft.com/en-us/library/z24kefs8(v=vs.110).aspx 我仍然缺少一些东西。我明天检查一下。已经非常感谢了。现在得下班,否则我会被困在这里直到明天;-) 好吧,原来我今天正在检查它。这有点让我陷入其中。我想解决这个问题。你能看看我发布的代码吗? @luke:对不起,现在我的工作已经结束了。如果你还在苦苦挣扎,我明天再看看【参考方案2】:

edit 代码未显示为DataTable 定义的PrimaryKey。这将配置DataAdapter 以执行更新并启用刷新DataTable。代码使用mysql,但在这方面,Provider 对象的工作方式都是一样的:

' persistant form level vars
Private daSample As MySqlDataAdapter
Private dtSample As DataTable
...

其他地方:

' there are caveats with WHERE clauses
Dim sql = "SELECT Id, Name, Country, Animal FROM SAMPLE WHERE Color = 'onyx'"

' using the ctor overload, no need for a DbCommand or Connection object
daSample = New MySqlDataAdapter(sql, MySQLConnStr)

' initialize the CommandBuilder, get other commands 
Dim cbSample = New MySqlCommandBuilder(daSample)

daSample.UpdateCommand = cbSample.GetUpdateCommand
daSample.InsertCommand = cbSample.GetInsertCommand
daSample.DeleteCommand = cbSample.GetDeleteCommand

dtSample = New DataTable()
daSample.FillSchema(dtSample, SchemaType.Source)
dtSample.PrimaryKey = New DataColumn() dtSample.Columns("id")

daSample.Fill(dtSample)

dgv1.DataSource = dtSample

从其他客户端应用中获取对数据库所做的更改:

daSample.Fill(dtSample)

初始显示:

在我从 UI 浏览器将一行更改为“onyx”后,Update 会显示更改后的行:

WHERE 子句可能有点问题。由于它限制了拉回的数据子集,Update 只会比较 new 结果集中的行。因此,如果我将 onlyx 行更改为“蓝色”,它将不会被删除。

一种解决方案是在表上使用.DefaultView.RowFilter,但这会减慢速度,因为它需要将所有行返回给客户端以在那里进行过滤。它并不完美。

【讨论】:

我删除了 commandbuilder 部分,因为它给了我一个例外。我几乎复制粘贴了其余代码,因为我没有为我找到丢失的行。它正在工作(没有重复的行,使用 .Fill 刷新后显示新行)只有一个小问题;当我有大约 1000 个条目时,调用 .Fill(Table) 刷新数据需要 30 秒。应该花那么多时间吗? 我不会冒险猜测为什么这么少的信息会很慢。使用StopWatch 类可以轻松地为几乎任何事情计时。 DGV 只会重新绘制正在显示的行,因此几乎可以肯定这不是罪魁祸首。

以上是关于SqlDataAdapter.Fill(DataGridView.DataSource) 复制所有行的主要内容,如果未能解决你的问题,请参考以下文章

SqlDataAdapter.Fill(DataGridView.DataSource) 复制所有行

SqlClient.SqlDataAdapter.Fill(DataSet) 结果如果不选择查询

SqlDataAdapter.Fill 方法慢

SqlDataAdapter.Fill 方法慢

SqlDataAdapter#Fill:`SelectCommand.connection` 属性尚未初始化

SqlDataAdapter.Fill 运行 SQL 命令两次