views:

842

answers:

5

Hey guys, so I've come across something which is perhaps a flaw in the Extension method .CopyToDataTable.

This method is used by Importing (in VB.NET) System.Data.DataTableExtensions and then calling the method against an IEnumerable. You would do this if you want to filter a Datatable using LINQ, and then restore the DataTable at the end.

i.e:

Imports System.Data.DataRowExtensions
 Imports System.Data.DataTableExtensions

 Public Class SomeClass
      Private Shared Function GetData() As DataTable
          Dim Data As DataTable

          Data = LegacyADO.NETDBCall


          Data = Data.AsEnumerable.Where(Function(dr) dr.Field(Of Integer)("SomeField") = 5).CopyToDataTable()


          Return Data

      End Function
 End Class

In the example above, the "WHERE" filtering might return no results. If this happens CopyToDataTable throws an exception because there are no DataRows.

Why?

The correct behavior should be to return a DataTable with Rows.Count = 0.

Can anyone think of a clean workaround to this, in such a way that whoever calls CopyToDataTable doesn't have to be aware of this issue?

System.Data.DataTableExtensions is a Static Class so I can't override the behavior....any ideas? Have I missed something?

cheers

UPDATE:

I have submitted this as an issue to Connect. I would still like some suggestions, but if you agree with me, you could vote up the issue at Connect via the link above

cheers

+2  A: 

If you feel it's a bug, then you should report it on Connect. Then post the URL of your bug as a comment or edit here, so those who like the idea can vote on it.

John Saunders
cool, thanks John. Can I just link to this question as it is, or do I have to make an edit? cheers
andy
@andy: It's up to you. Do link to the question, but the better the question, the better chance they'll understand and fix the bug.
John Saunders
cool, thanks man. I but a shorter description at Connect (which maybe I should have done here....hmm....)
andy
+2  A: 

Until Microsoft fix this issue, here's a work around:

Create your own Extension method which uses the CopyToDataTable method if there are DataRows, if there aren't, then it returns an empty DataTable.

VB.NET

    Imports System.Data

Namespace CustomExtensions
    Public Module DataRowExtensionsOverride

        <System.Runtime.CompilerServices.Extension()> _
        Public Function CopyToDataTableOverride(Of T As DataRow)(ByVal Source As EnumerableRowCollection(Of T)) As DataTable

            If Source.Count = 0 Then
                Return New DataTable
            Else
                Return DataTableExtensions.CopyToDataTable(Of DataRow)(Source)
            End If

        End Function

    End Module
End Namespace

C#;

public static class DataRowExtensionsOverride
    {

        public static DataTable CopyToDataTableOverride<T>(this IEnumerable<T> Source) where T : DataRow {

            if (Source.Count() == 0) {
                return new DataTable();
            } else {
                return DataTableExtensions.CopyToDataTable<T>(Source);
            }
        }
    }
andy
A: 

Do yo have have sample code in c# working, I have the same problem.

Ronnie
yep, I've just updated my answer above, or you can try Vince's solution
andy
+1  A: 
someDataTable.AsEnumerable().Where(r => r.Field<string>("SomeField") == "SomeValue").AsDataView().ToTable();

.AsDataView().ToTable() returns an empty table with the same structure as someDataTable if there are now rows returned from .Where()

Vince
cool, I'll try it out, cheers vince
andy
one issue i see with your custom extension is the check for .Count. If i'm not mistaken, .Count forces the a read of the entire enumeration. Therefore, if your count is say, 1000, then you're reading the entire enumeration then calling CopyToDataTable() which probably forces another read. Have you considered checking if .GetEnumerator().MoveNext() == true? If this is true, then the enumeration has at least one row, and that's all your concerned about, not the count.
Vince
good point vince, you're totally right. I'll update it, cheers!
andy
+1  A: 

I came across this problem today and worked out a workaround if it helps.

Sorry, but the blog is in C#, but I just used an IEnumerable on the LINQ variable and check .Current to see if it had returned any rows.

Dominic Zukiewicz