VB.Net 合并不遵守主键约束的数据表
VB.Net Merging datatables not obeying primary key constraints
我在使用 DataTable.Merge 方法和防止行重复时遇到困难。我有多个数据表需要合并为一个,包括需要合并的重复列。
我的数据表如下所示:
PID|140 PID|140 PID|144 PID|142
1 | X 1| 1| 1|X
2 | 2|X 2|X 2|X
3 | 3| 3|X 3|X
当我合并它们时,它创建了重复的行值。
What I get: What I actually want:
PID|140|144|142 PID|140|144|142
1 | X | | 1 | X | | X
2 | | | 2 | X | X | X
3 | | | 3 | | X | X
1 | | |
2 | X | |
3 | | |
1 | | |
2 | | X |
3 | | X |
1 | | | X
2 | | | X
3 | | | X
我正在设置主键并在架构选项上使用 addWithKey,但合并时似乎忽略了主键约束。
'writeTable being the destination of the merges'
Dim primaryKey(1) As DataColumn
primaryKey(1) = writeTable.Columns("PID")
writeTable.PrimaryKey = primaryKey
'...merging from a selected dataview to table'
selected = view.ToTable("Selected", False,"PID","144")
primaryKey(1) = selected.Columns("PID")
selected.PrimaryKey = primaryKey
writeTable.Merge(selected, False, MissingSchemaAction.AddWithKey)
Merge 旨在使用数据库中的更改来更新 DataTable。当您 Merge writeTable with selected 且第二个参数为 False 时,您会从 selected 中获得新值,1,Nothing 2,X 3,Nothing。
每个值都不同于初始值,因此初始值将被覆盖。当第二个参数为True时,得到1,X 2,Nothing 3,Nothing。初始值被保留。如果您希望 1 和 2 在 140 列中都显示 X,则必须过滤所选 table 以排除 140 列中的空值。然后只有 selected 中的非空值才会覆盖初始值。我是这样做的
Dim NonNullselected = selected.Select($"[140] Is Not Null").CopyToDataTable
140左右的括号是必须的。必须处理以数字开头的字段。
我认为您的主要问题是分配主键。
Dim primaryKey(1) As DataColumn
这将创建一个包含 2 个元素的 DataColumn 数组,索引为 0 和 1。
primaryKey(1) = writeTable.Columns("PID")
这将向数组的第二个元素添加一列。第一个元素是 Nothing.
writeTable.PrimaryKey = primaryKey
我可以看出这是如何没有成功创建 PK。
我是这样做的
dt.PrimaryKey = {dt.Columns(0)}
对于您的代码,
writeTable.PrimaryKey = {writeTable.Columns("PID")}
大括号表示预期的数组,因此 属性 可以处理复合键。
Private writeTable As DataTable
Private selected As DataTable
Private Table3 As DataTable
Private Table4 As DataTable
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
CreateAndFillTables()
Dim NonNullselected = selected.Select($"[140] Is Not Null").CopyToDataTable
writeTable.Merge(NonNullselected, False, MissingSchemaAction.AddWithKey)
writeTable.Merge(Table3, False, MissingSchemaAction.AddWithKey)
writeTable.Merge(Table4, False, MissingSchemaAction.AddWithKey)
DataGridView1.DataSource = writeTable
End Sub
Private Sub CreateAndFillTables()
writeTable = CreateTable("140")
writeTable.Rows.Add({1, 0})
writeTable.Rows.Add({2})
writeTable.Rows.Add({3})
selected = CreateTable("140")
selected.Rows.Add({1})
selected.Rows.Add({2, 0})
selected.Rows.Add({3})
Table3 = CreateTable("144")
Table3.Rows.Add(1)
Table3.Rows.Add(2, 0)
Table3.Rows.Add(3, 0)
Table4 = CreateTable("142")
Table4.Rows.Add(1, 0)
Table4.Rows.Add(2, 0)
Table4.Rows.Add(3, 0)
End Sub
Private Function CreateTable(SecondColumnName As String) As DataTable
Dim dt As New DataTable
dt.Columns.Add("PID", GetType(Integer))
dt.Columns.Add(SecondColumnName, GetType(Integer))
dt.PrimaryKey = {dt.Columns(0)}
Return dt
End Function
结果
我在使用 DataTable.Merge 方法和防止行重复时遇到困难。我有多个数据表需要合并为一个,包括需要合并的重复列。
我的数据表如下所示:
PID|140 PID|140 PID|144 PID|142
1 | X 1| 1| 1|X
2 | 2|X 2|X 2|X
3 | 3| 3|X 3|X
当我合并它们时,它创建了重复的行值。
What I get: What I actually want:
PID|140|144|142 PID|140|144|142
1 | X | | 1 | X | | X
2 | | | 2 | X | X | X
3 | | | 3 | | X | X
1 | | |
2 | X | |
3 | | |
1 | | |
2 | | X |
3 | | X |
1 | | | X
2 | | | X
3 | | | X
我正在设置主键并在架构选项上使用 addWithKey,但合并时似乎忽略了主键约束。
'writeTable being the destination of the merges'
Dim primaryKey(1) As DataColumn
primaryKey(1) = writeTable.Columns("PID")
writeTable.PrimaryKey = primaryKey
'...merging from a selected dataview to table'
selected = view.ToTable("Selected", False,"PID","144")
primaryKey(1) = selected.Columns("PID")
selected.PrimaryKey = primaryKey
writeTable.Merge(selected, False, MissingSchemaAction.AddWithKey)
Merge 旨在使用数据库中的更改来更新 DataTable。当您 Merge writeTable with selected 且第二个参数为 False 时,您会从 selected 中获得新值,1,Nothing 2,X 3,Nothing。 每个值都不同于初始值,因此初始值将被覆盖。当第二个参数为True时,得到1,X 2,Nothing 3,Nothing。初始值被保留。如果您希望 1 和 2 在 140 列中都显示 X,则必须过滤所选 table 以排除 140 列中的空值。然后只有 selected 中的非空值才会覆盖初始值。我是这样做的
Dim NonNullselected = selected.Select($"[140] Is Not Null").CopyToDataTable
140左右的括号是必须的。必须处理以数字开头的字段。
我认为您的主要问题是分配主键。
Dim primaryKey(1) As DataColumn
这将创建一个包含 2 个元素的 DataColumn 数组,索引为 0 和 1。
primaryKey(1) = writeTable.Columns("PID")
这将向数组的第二个元素添加一列。第一个元素是 Nothing.
writeTable.PrimaryKey = primaryKey
我可以看出这是如何没有成功创建 PK。
我是这样做的
dt.PrimaryKey = {dt.Columns(0)}
对于您的代码,
writeTable.PrimaryKey = {writeTable.Columns("PID")}
大括号表示预期的数组,因此 属性 可以处理复合键。
Private writeTable As DataTable
Private selected As DataTable
Private Table3 As DataTable
Private Table4 As DataTable
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
CreateAndFillTables()
Dim NonNullselected = selected.Select($"[140] Is Not Null").CopyToDataTable
writeTable.Merge(NonNullselected, False, MissingSchemaAction.AddWithKey)
writeTable.Merge(Table3, False, MissingSchemaAction.AddWithKey)
writeTable.Merge(Table4, False, MissingSchemaAction.AddWithKey)
DataGridView1.DataSource = writeTable
End Sub
Private Sub CreateAndFillTables()
writeTable = CreateTable("140")
writeTable.Rows.Add({1, 0})
writeTable.Rows.Add({2})
writeTable.Rows.Add({3})
selected = CreateTable("140")
selected.Rows.Add({1})
selected.Rows.Add({2, 0})
selected.Rows.Add({3})
Table3 = CreateTable("144")
Table3.Rows.Add(1)
Table3.Rows.Add(2, 0)
Table3.Rows.Add(3, 0)
Table4 = CreateTable("142")
Table4.Rows.Add(1, 0)
Table4.Rows.Add(2, 0)
Table4.Rows.Add(3, 0)
End Sub
Private Function CreateTable(SecondColumnName As String) As DataTable
Dim dt As New DataTable
dt.Columns.Add("PID", GetType(Integer))
dt.Columns.Add(SecondColumnName, GetType(Integer))
dt.PrimaryKey = {dt.Columns(0)}
Return dt
End Function
结果