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 并使用它的主要内容,如果未能解决你的问题,请参考以下文章

python将txt导入到excel

如果文件夹中存在 zip 文件,VBA 将无法仅限于 .dat 文件

python编程:如何将一个包含若干整数的List写入dat文件中

python编程:如何将一个包含若干整数的List写入dat文件中

dat类型文件入库后校验数据有问题

delphi 中如何将图片数据保存到dat文件里的,然后读取出来,并在Image控件中显示。