I have an issue with the DataTable object. Although I think it's a cultural thing. Some people I talk to don't seem to bothered by it. I find it very annoying, mostly because it would have been so easily avoided.
So whats the problem? When a DataRow is flagged for deletion it's still part of the row collection in the DataTable. So you may now be wondering what the big deal is.
You see I spent 10 years in the PowerBuilder world. In a PowerBuilder DataWindow (Similar to the objects in ADO.NET) when a row is flagged for deletion it's stored in a separate collection. Therefore when you are processing the rows The Deleted rows are not in the collection of current rows. If you want to access the deleted rows you can do that also. Also when you get a count of rows it's the count of rows not including the deleted rows.
In a DataTable when you delete a row it remains in the rows Collection and you have to deal with them. This also means that DataTable.Rows.Count or DataTable.Count is a count of all the rows including deleted rows.
Why do I say it's cultural? My esteemed colleague Bruce Johnson and I had a brief discussion and he almost convinced me this is how it should be. Bruce said "It's only flagged as deleted why shouldn't it be in the Rows collection?" I have to say this is a fair statement. However it would make life easier for the developer if there was a DeletedRows collection. Therefore a corresponding DeletedRows.Count. This feels more natural to me.
When do you ever want to iterate through all the rows in a DataTable both deleted and not and preform the same action on them? I could make something up but it would be bogus. I have never wanted to do this. Even if you can come up with a good reason it's not going the be the common scenario. When you write a framework you should take into account the 80/20 rule. Make it easier for 80 percent of the cases and let the 20 percent do extra work.
This means that when you iterate through a collection of rows in a table you have to be sensitive to the fact that some of them may have been deleted.
There are ways to make life easier, and when .net 2.0 (Whidbey) comes along there will be even more.
What can you do about it?
You could check the row state inside your iterator like this.
For each row as dataRow in DataTable
if Datarow.RowState <> dataRowState.Delete then
...
end if
Next
Or you could get a subset of the collection like this.
For each row as dataRow in dataTable.Select("", "", DataViewRowState.CurrentRows)
...
next
Keep in mind with this solution if you are using a typed DataSet you will have to cast the select for the typed row.
For each row as OrderRow in Ctype(OrderTable.Select("","",DataViewRowState.CurrentRows), OrderRow())
...
next
I recommend wrapping up the select in a DataSetHelper method, so it looks like this.
For each row as OrderRow in Ctype(DataSetHelper.GetCurrentRows( OrderTable ), OrderRow())
...
next
What about getting the count of Current rows in the DataTable. You could wrap this little code segment up in a method in your DataSetHelper also. Just pass in a DataTable.
Public Function GetRowCount( dt as DataTable ) as integer
Dim dataView As New dataView
dataView.Table = dt
dataView.RowStateFilter = DataViewRowState.CurrentRows
return = dataView.Count
End Function
I mentioned above .net 2.0 (Whidbey) will help. How is that you ask.
There are a couple of solutions.
-
Using Partial types you could extend the DataSet Class to include a method that returns a collection of Current Rows. This way it's more natural to the developer. OrderTable.CurrentOrderRows
-
Using Iterators you could write your own iterator that only iterates thought the current rows.