DataSet.Merge - 将类型化的 DataSet/DataTable 合并到另一个 DataSet 并使用它
Posted
技术标签:
【中文标题】DataSet.Merge - 将类型化的 DataSet/DataTable 合并到另一个 DataSet 并使用它【英文标题】:DataSet.Merge - Merge typed DataSet/DataTable to another DataSet and work with it 【发布时间】:2022-01-18 15:11:26 【问题描述】:我已经在 GitHub https://github.com/microsoft/referencesource/issues/160 上问过这个问题,并且 微软问答,直到现在还没有得到答案。我希望大型 *** 社区可以帮助我:)
这是我最初的问题:https://social.msdn.microsoft.com/Forums/en-US/4f698731-db76-4eb0-a86d-d77d6a852644/datasetmerge-merge-typed-dataset-to-another-and-work-with-it?forum=adodotnetdataset#c53484c0-c6a1-4b8c-926f-f3e9ec2bc966
我有两个数据集,每个数据集都有一个数据表。 现在我有这个代码,例如:
MainSet mainSet = new MainSet();
SubSet subSet = new SubSet();
subSet.SubTable.AddSubTableRow("test1", "test12", "test13");
subSet.SubTable.AddSubTableRow("test2", "test22", "test13");
subSet.SubTable.AddSubTableRow("test3", "test32", "test33").SetDataColumn3Null();
subSet.AcceptChanges();
mainSet.Merge(subSet.SubTable);
if(mainSet.Tables["SubTable"] is SubSet.SubTableDataTable subSetTable)
var emptyRows = subSetTable.Where(row => row.IsDataColumn3Null()).ToArray();
if (emptyRows.Any())
Console.WriteLine("Found empty rows.");
对旧帖请求的一个答案:是的,我们使用中间层架构,需要将第二个 DataSet 合并到“MainSet”,因为第二个 DataSet 再次被其他 BusinessRules 重用......
演员表不是问题,这是正确的。但是像“row.IsDataColumn3Null()”这样的调用不起作用,因为我得到了一个像“DataColumn3不属于表子表”这样的异常。
现在我知道了为什么会出现这个异常,因为我为此研究了 .NET 代码。 但我不知道以这种方式实现的原因,我希望我能联系到 ADO.NET 团队的人,他们可以给我一个答案。
我得到这个异常的原因是因为 DataRow 的 CheckColumn 方法检查行的表和列的表是否相等。但是合并后该列的表为空。 合并在做什么?
简而言之:DataTable 的内部 Clone(DataSet dataSet) 方法在 Merge-Process 期间被调用。 SubTable 的一个实例是通过 Activator.CreateInstance 创建的。 ...这就是为什么演员阵容正确 之后,它检查列是否可用并调用新实例的 Reset() 方法。在这一刻,表格的所有列都被删除。并且对数据列的引用正在丢失表格。稍后在 DataTable 中的 CloneTo(...) 方法中,再次添加原始表的列。 我认为他们这样做是因为您可以操作列或将列添加到表中。只需创建一个实例,您就没有这些更改....
但现在我查看代码中生成的设计器文件并找到“InitVars”方法。这种方法可以满足我的需要。但是因为该方法是内部的,所以我不能从另一个解决方案中调用此方法,我只是添加对定义了我的 DataSet 的 dll 的引用。
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "16.0.0.0")]
internal void InitVars()
this.columnDataColumn3 = base.Columns["DataColumn3"];
this.columnDataColumn2 = base.Columns["DataColumn2"];
this.columnDataColumn1 = base.Columns["DataColumn1"];
此代码将基本 Column 分配给成员 this.columnDataColumn3 并且当我在演员后直接调用 InitVars 时,我上面的所有代码都将起作用。 但是现在向 DataTable 的开发人员提出问题(:))为什么 InitVars 不是 DataTable 中的虚拟方法并在合并后(再次添加列后)调用它?
或其他可行的解决方案:
为 DataColumn3Column 创建此代码的代码生成器(在 IsDataColumn3Null() 等方法中使用)
public global::System.Data.DataColumn DataColumn3Column
get
return this.columnDataColumn3;
为什么没有生成这段代码:
public global::System.Data.DataColumn DataColumn3Column get return base.Columns["DataColumn3"];
这可能是性能问题吗?
致以诚挚的问候 托尔斯滕
【问题讨论】:
【参考方案1】:我能够重现您的问题。 (对于那些在家玩的人,为了重现该问题,“MainSet”在设计时不应包含名为“SubTable”的表)。 一种解决方法是通过反射调用受保护的 InitVars。 例如:
if (main.Tables["SubTable"] is SubSet.SubTableDataTable subSetTable)
System.Reflection.MethodInfo mi = subSetTable.GetType().GetMethod("InitVars", System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
if (mi == null)
throw new ApplicationException("could not get InitVars method info");
mi.Invoke(subSetTable, null); // call InitVars via reflection
var emptyRows = subSetTable.Where(row => row.IsDataColumn3Null()).ToArray();
我真的很惊讶:
if (main.Tables["SubTable"] is SubSet.SubTableDataTable subSetTable)
返回 true,因为 main 属于类型化数据集:MainSet,并且 Subset.SubTableDataTable 是在另一个类型化数据集中定义的。 通常,对于此类代码,我希望 MainSet 类型数据集也具有在设计时定义的 SubSet 数据表。 然后在合并之后,可以将main.SubTable作为MainSet.SubTableDataTable引用,并且可以正常工作,无需调用InitVars。但我想这种方法可能不适合您的要求。
【讨论】:
if (main.Tables["SubTable"] is SubSet.SubTableDataTable subSetTable) 为真,因为它们复制了特殊类型而不是无类型。 (查看源代码)。他们在 Merge 后不自动调用 InitVars 肯定是有原因的。是的,我们不能将所有可能的“子表”添加到主集。以上是关于DataSet.Merge - 将类型化的 DataSet/DataTable 合并到另一个 DataSet 并使用它的主要内容,如果未能解决你的问题,请参考以下文章
如果文件夹中存在 zip 文件,VBA 将无法仅限于 .dat 文件
python编程:如何将一个包含若干整数的List写入dat文件中