Showing posts with label LINQ. Show all posts
Showing posts with label LINQ. Show all posts

Introduction to Linq To Datatables

LINQ to objects will work on any object that implements IEnumerable (the same interface that allows an object to be used in a For Each loop). Datasets are objects, but they don’t implement IEnumerable by default, so you’ll need to first add a reference to a library that adds some extension methods that wrap DataTable and allow it to be enumerated.

Just go to Project > References > Add > .NET > System.Data.DataSetExtensions

DataSetExtensions

In LINQ, you always start the query with the From statement

From a In b    

This gives you access to each item that is part of the B collection in the same way that a for loop does

For Each a In b

For the rest of the for loop (or linq query), you can just refer to a and it’s automatically populated as it iterates over the collection.

If you want to loop over a DataTable, you need to create an enumerable table by calling DataTable.AsEnumerable() in order to convert the collection of rows into one that is, well, enumerable. When you loop over a DataTable, you’ll be holding a row object, so you can generally query it in the same way that you otherwise would

If I have a DataRow object, I can get the values like this:

'longhand
Dim name = myRow.Field(Of String)("Name")

'shorthand
Dim name = myRow("Name")

Let’s say that we have the following SQL Query that we’d like to do in .NET with Datatables instead:

SELECT p.ID, p.Name, e.SSN
FROM People p
JOIN ExtendedInfo e 
  ON p.ID = e.PersonID

LINQ (especially using it’s Query Syntax) is intended to function a lot like SQL. So here’s what it would look like in .NET:

Dim query = From person In people.AsEnumerable
    Join extra In extendedInfo.AsEnumerable()
      On person("ID") Equals extra("PersonID")
    Select New With {
            .ID = person("ID"),
            .Name = person("Name"),
            .SSN = extra("SSN")
    }

The syntax on the bottom just creates a new anonymous object and then selects it. We can Select any object available from the query (i.e. person) or we can create our own on the fly and select that

If you’re unfamiliar with anonymous objects, the syntax may look unfamiliar, but it’s a pretty basic concept. One rarely used feature you might not know about is that if we want to initialize a Person class (which has a Name Property), we can set the name property directly from the initializer using a With {} statement like this:

Dim typedPerson = New Person With {
    .Name = "Angelic"
}

If we don’t have a Person class to stuff our data in, or we just want to do it on the fly, we can do the same thing by omitting the class name and then just passing in any properties we want our new class to have.

Note: The compiler will actually create a class for you behind the scenes that has all the properties you’ve specified, but we don’t have a name for it - thus it’s anonymous.

'Anonymous Person
Dim anonPerson = New With {
    .Name = "Angelic"
}

Now we have a query that, once evaluated, will return the joined tables into an enumerable collection of anonymous objects. If we want to convert that back into a new Datatable it’s as simple as calling CopyToDataTable on the query result:

Dim newTable = query.CopyToDataTable()

However, when you do this right now, you’ll get the following error:

CopyToDataTable is not a member of System.Collections.Generic.IEnumerable(Of <anonymous type>)

Okay, I lied - It would be simple if the enumerable was of type DataRow. But not to fear, as written by this MSDN article on How to Implement CopyToDataTable Where the Generic Type T Is Not a DataRow, you just need to include some extra extension methods that don’t ship with DataSetExtensions .

Just add this file to your project anywhere.

Now the code should compile and work fine.

You can test the result by running:

For Each row In newTable.AsEnumerable()
Console.WriteLine("ID: "   & row("ID") & " / " &
                  "Name: " & row("Name") & " / " &
                  "SSN: "  & row("SSN"))
Next

If you’d like to run this code immediately without even opening up Visual Studio, you can see a working demo in dotNetFiddle here.

For further reading, there is a TON of great information on MSDN under

LINQ to DataSet - Getting Started | Programming Guide

List (Of LINQ Enumerable Methods)

Here’s a grouped listing of all the methods available on the IEnumerable Class.
Methods which can be composed using VB Query Syntax are generally listed first and are also highlighted yellow.

Projection Operations

  • Select - Projects each element of a sequence into a new form.
  • SelectMany - Projects each element of a sequence to an IEnumerable(Of T) and flattens the resulting sequences into one sequence.

Partitioning Data

  • Skip - Bypasses a specified number of elements in a sequence and then returns the remaining elements.
  • SkipWhile - Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements.
  • Take - Returns a specified number of contiguous elements from the start of a sequence.
  • TakeWhile - Returns elements from a sequence as long as a specified condition is true.

Join Operations

  • Join - Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys.
  • GroupJoin - Correlates the elements of two sequences based on equality of keys and groups the results.

Grouping Data

  • GroupBy - Groups the elements of a sequence according to a specified key selector function.

Filtering Data

  • Where - Filters a sequence of values based on a predicate.
  • OfType - Filters the elements of an IEnumerable depending on their ability to be cast to a specified type.

Sorting Data

  • OrderBy - Sorts the elements of a sequence in ascending order according to a key.
  • OrderByDescending - Sorts the elements of a sequence in descending order according to a key.
  • ThenBy - Performs a subsequent ordering of the elements in a sequence in ascending order according to a key.
  • ThenByDescending - Performs a subsequent ordering of the elements in a sequence in descending order, according to a key.
  • Reverse - Inverts the order of the elements in a sequence.

Aggregation Operations

  • Average - Computes the average of a sequence of values.
  • Count - Returns the number of elements in a sequence.
  • LongCount - Returns an Int64 that represents the total number of elements in a sequence.
  • Max - Returns the maximum value in a sequence of values.
  • Min - Returns the minimum value in a sequence of values.
  • Sum - Computes the sum of a sequence of values.
  • Aggregate - Applies an accumulator function over a sequence.

Set Operations

  • Distinct - Returns distinct elements from a sequence by using the default equality comparer to compare values.
  • Except - Produces the set difference of two sequences by using the default equality comparer to compare values.
  • Intersect - Produces the set intersection of two sequences by using the default equality comparer to compare values.
  • Union - Produces the set union of two sequences by using the default equality comparer.
  • Concat - Concatenates two sequences.
  • Zip - Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.

Quantifier Operations

  • All - Determines whether all elements of a sequence satisfy a condition.
  • Any - Determines whether a sequence contains any elements.
  • Contains - Determines whether a sequence contains a specified element by using the default equality comparer.

Generation Operations

  • DefaultIfEmpty - Returns the elements of the specified sequence or the type parameter’s default value in a singleton collection if the sequence is empty.
  • Empty - Returns an empty IEnumerable(Of T) that has the specified type argument.
  • Range - Generates a sequence of integral numbers within a specified range.
  • Repeat - Generates a sequence that contains one repeated value.

Element Operations

  • First - Returns the first element of a sequence.
  • FirstOrDefault - Returns the first element of a sequence, or a default value if the sequence contains no elements.
  • Last - Returns the last element of a sequence.
  • LastOrDefault - Returns the last element of a sequence, or a default value if the sequence contains no elements.
  • ElementAt - Returns the element at a specified index in a sequence.
  • ElementAtOrDefault - Returns the element at a specified index in a sequence or a default value if the index is out of range.
  • Single - Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.
  • SingleOrDefault - Returns the only element of a sequence, or a default value if the sequence is empty; this method throws an exception if there is more than one element in the sequence.

Equality Operations

  • SequenceEqual - Determines whether two sequences are equal by comparing the elements by using the default equality comparer for their type.

Converting Data Types

  • Cast - Casts the elements of an IEnumerable to the specified type.
  • AsEnumerable - Returns the input typed as IEnumerable(Of T).
  • AsQueryable - Converts a (generic) IEnumerable to a (generic) IQueryable.
  • ToArray - Creates an array from a IEnumerable(Of T).
  • ToDictionary - Creates a Dictionary(Of TKey, TValue) from an IEnumerable(Of T)according to a specified key selector function.
  • ToList - Creates a List(Of T) from an IEnumerable(Of T).
  • ToLookup - Creates a Lookup(Of TKey, TElement) from an IEnumerable(Of T)according to a specified key selector function.