ObjectSharp Blogs

You are currently viewing

Dave Lloyd's 2 Cents

A .NET Developer's Perspective


DataTable.Rows

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.

  1. 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
  2. Using Iterators you could write your own iterator that only iterates thought the current rows.

 

 

 

 

Comments

  • dave February 3, 2004 2:46 PM

    You could also create a Dataview on the table with a RowStateFilter to exclude the deleted rows to mimic the collection you have in PB, or to exclude all other row states to mimic the Deleted rows buffer in PB.

  • dave March 19, 2004 7:34 PM

    Dave,

    I too found that somewhat frustrating and have ended up using the very same technique as described by Barry.

    That said, I find the most interesting thing about this piece is the fact that you used VB for the examples...

  • dave March 29, 2004 8:15 AM

    Andrew...

    Havn't you heard VB is a real language finally. :)

  • dave August 3, 2005 12:44 PM

    what really gets me is that they are included in the collection, but you can't access them:

    Deleted row information cannot be accessed through the row.

    So why are they included????

  • dave December 1, 2005 1:20 AM

    xnera..
    A deleted row cannot be accessed, but it is not removed unlest you use the acceptChanges function on the dataset. If the acceptChanges function is not called, the deleted row is not deleted from the underlying database with the dataAdapter's update command.

  • dave March 27, 2006 10:39 PM

    TEST1
    <code>Dim dt As New DataTable</code>
    then add 3 rows
    then delete 1 row
    now...
    <code>dt.Rows.Count</code> will return 2
    <code>dt.Select.Length</code> will return 2 also

    TEST2
    <code>Dim dt As New DataTable</code>
    then add 3 rows
    then <code>dt.AcceptChanges()</code>
    then delete 1 row
    now...
    <code>dt.Rows.Count</code> will return 3
    <code>dt.Select.Length</code> will return 2

    So we know...
    1. <code>dt.Select</code> by default select <code>DataViewRowState.CurrentRows</code> only
    2. <code>DataViewRowState.Added</code> will be removed from the collection immediately before <code>dt.AcceptChanges()</code>

    And in my opinion,
    <code>For each row as OrderRow in Ctype(OrderTable.Select("","",DataViewRowState.CurrentRows), OrderRow())
    ...
    next</code>
    equals
    <code>For each row as OrderRow in OrderTable.Select
    ...
    next</code>
    because
    1. the default selection I memtioned above
    2. the casting will do to the object by the code <code>as OrderRow</code>

    If there is any mistake above, let me know please...

  • dave March 31, 2006 10:20 AM

    Datatable.GetChanges(DataRowState.Deleted).Rows.Count or Datatable.GetChanges(DataRowState.Deleted) will help get the deleted rows count or the datatble consisting of deleted records.

Leave a Comment

(required) 
(optional)
(required) 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS