DataSet.Merge - Merge typed DataSet to another and work with it...

Thorsten Steinberg 1 Reputation point
2021-11-11T13:33:26.203+00:00

Hello everybody,
this question belongs to a previous question i asked here: datasetmerge-merge-typed-dataset-to-another-and-work-with-it

After 10 years I want to know an answer :) (It's a shame I didn't gave an answer to the post in the past (@allen _MSDN)).

So I have two DataSets which each one has one DataTable.
Now I have this code for example:

            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.");  
                }  
            }  

One answer to a requestion of the old post: Yes we use a middle tier architecture and need to merge the second DataSet to the "MainSet" because the second DataSet is reused by other BusinessRules again....

The Cast isn't the problem, this works correct. But then the call like "row.IsDataColumn3Null()" doesn't work, because I get an exception like "DataColumn3 does not belongs to table SubTable".

Now I know a little bit why I get this exception because I studied the .NET Code for this.
But I don't know the reason why this is implemented in this way and I hope I reach someone from the ADO.NET Team who can give me an answer.

The reason why I get this exception is because the CheckColumn Method of the DataRow checks the Table of the Row with the Table of the Column if they are equal. But the Table of the column is null after the Merge.
What is Merge doing?

In a short way: the internal Clone(DataSet dataSet) Method from DataTable is called during the Merge-Process.
An instance of SubTable is created via the Activator.CreateInstance. ... This is why the cast works correct
After that it checks if columns available and called the Reset() Method of the new instance. In this moment all columns of the table are removed. And the reference to the datacolumn is loosing the table. Later in CloneTo(...) Method from DataTable, the columns of the original table are add again.
I think they do this because you can manipulate columns or add columns to a table. With only creating an instance you don't have had these changes....

But now I look at the designer file generated in the code and find the "InitVars" method. This method does what I need. But because the method is Internal, I can't call this method from another solution where I just add a reference to the dll where my DataSet is defined.

            [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"];  
            }  

This code is assigning the base Column to the member this.columnDataColumn3 and all of my code above is would be working when I call InitVars directly after the cast.
But now the question to the developers of the DataTable ( :) ) Why isn't InitVars a virtual method in DataTable and calling this after the merge (after adding the columns again) ?

Or another solution that would be work:

The code generator creating this code for DataColumn3Column (which is using in method like IsDataColumn3Null() etc.)

            public global::System.Data.DataColumn DataColumn3Column {  
                get {  
                    return this.columnDataColumn3;  
                }  
            }  

Why isn't this code generated:

public global::System.Data.DataColumn DataColumn3Column {  
                get {  
                    return base.Columns["DataColumn3"];  
                }  
            }  

Could this be a performance issue?

So I hope realy that someone from microsoft/ADO.NET Team (or who had implement it) can give me an answer to my questions.

With kind regards
Thorsten

.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,367 questions
{count} votes