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) 结果如果不选择查询