How LINQ to Dataset works in VB (Jonathan Aneja)

LINQ at its core requires any data source to be queryable, which basically means it must implement IEnumerable.  (It’s actually a bit more complicated than that, for a full explanation see section 11.21.2 of the Visual Basic 9.0 Language Specification).  Now when working with LINQ to Dataset we have a problem: DataTable does not implement IEnumerable, so how can we query over it?

 

As we saw yesterday, Visual Studio 2008 includes an assembly called System.Data.DataSetExtensions.dll, which defines an extension method called AsEnumerable().  Here’s what this method looks like:

    <Extension()> _

    Public Function AsEnumerable(source As DataTable) As EnumerableRowCollection(Of DataRow)

 

Basically this takes in a DataTable and sends back something that implements IEnumerable(Of T), which LINQ can then consume using the standard query operators.  So all you have to do is import System.Data (which is done by default in the project templates) and then you can use LINQ against a Dataset by calling AsEnumerable(). 

 

    Dim customers = TestDS.Tables(“Customers”)

 

    Dim franceCustomers = From cust In customers.AsEnumerable() _

                          Where cust!Country = “France” _

                          Select cust

 

Now one of the interesting things about the way LINQ works in VB is you don’t actually have to call AsEnumerable() explicitly for the code above to compile.  Even though DataTable does not implement IEnumerable, the compiler helps out here by looking for methods that can turn it into something queryable.  When the VB compiler encounters a LINQ query over a type that does not implement IEnumerable, IEnumerable(Of T), IQueryable, or IQueryable(Of T) it then does the following, in order:

1.       See if there is a conforming Select method available on the type.

2.       See if the type has an instance method named AsQueryable which returns a type that is queryable. 

3.       See if the type has an extension method in scope named AsQueryable which returns a type that is queryable. 

4.       See if the type has an instance method named AsEnumerable which returns a type that is queryable. 

5.       See if the type has an extension method in scope named AsEnumerable which returns a type that is queryable.

 

If at any point the compiler finds a method that matches, it inserts a call to it.  When the System.Data namespace is imported, the compiler finds a match for DataTable on step 5, and inserts the call to AsEnumerable for you.  As a result you can write LINQ to Dataset code like this example from the 101 LINQ Samples:

 

        Dim customers = TestDS.Tables(“Customers”)

 

        Dim franceCustomers = From cust In customers _

                              Where cust!Country = “France” _

                              Select cust

 

What this means is that you can LINQ-enable your types by providing an AsEnumerable extension method that returns something that is queryable.

 

Note that for strongly-typed Datasets you don’t need to call AsEnumerable, as they inherit from TypedTableBase(Of T) which implements IEnumerable.  This is a new type in VS2008; in VS2005 the Dataset Designer would generate code that inherited from DataTable and then explicitly implemented IEnumerable itself.