Linq Tutorial (Part 3): Query Method Sintax

Description
Table of Contents
Summary

Sintax used to build queries using the Standard Query Operator API that are defined as extension methods. These methods can be groupped in several categories.

Description

The sintax of query method follow a base template:

[source collection].[extension method][.extension method]*

The Standard Query Operators are implemented on two sets namely  for IEnumerable<T> and IQueryable<T> interfaces.

The IEnumerable<T> operators that require predicates or anonymous functions expects Func<T,..,TResult> delegates. Each of these functions are executed at client-side and should only be used on Linq To Objects.

The IQueryable<T> operators that require predicates or anonymous functions expects as parameters Expression<Func<T,..,TResult>> for predicates or anonymous functions.

The Expression<T,..,TResult> is an expression tree half-compiled and represents a query on .NET.
This expression tree is only parsed and converted to SQL at server side by the implementation of the IQueryProvider (e.g. Linq To SQL)

Example:

IEnumerable<Person> people = GetEnumerablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();

IQueryable<Person> people = GetQueryablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();

In the first code block  ”x=> x.Age > 18″  is interpreted as a anonymous method of type Func<Person, bool> and is executed as a normal method, at client-side, once per each person in the collection, at memory-level.

In the second code block “x=> x.Age > 18″ is interpreted as an expression tree  Expression<Func<Person, bool>> and will be executed once, at server-side,  embebbed with the entire query, on the database.

The operators described next are presented for the IEnumerable<T> interface and should be considered only for object queries at memory-level. The same operators exist for the IQueryable<T> interface and must be considered for databse queries.

Operations
Projecting Operators

Performs transformation for each element selected. These elements will be included in a anonymous type or DTO class type.

How to do it
// Project each element of a sequence into a new form 

public static IEnumerable<TResult> Select<TSource, TResult>(
        this IEnumerable<TSource> source,
        Func<TSource, TResult> selector
)

// Project each element of a sequence into a new form by incorporating the element's index 

public static IEnumerable<TResult> Select<TSource, TResult>(
        this IEnumerable<TSource> source,
        Func<TSource, int, TResult> selector
)

// Projects each element of a sequence to an IEnumerable<T> and flattens the resulting sequences into one single sequence

public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(
        this IEnumerable<TSource> source,
        Func<TSource, IEnumerable<TResult>> Selector
)

// Projects each element of a sequence to an IEnumerable<T> , flattens the resulting sequences into one single sequence and invokes a result selector function on each element therein.

public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(
        this IEnumerable<TSource> source,
        Func<TSource, IEnumerable<TCollection>> collectionSelector,
        Func<TSource, TCollection, TResult> resultSelector
)
How to use it

Samples for the Select Manymethod:

The following example creates a sequence of the orders of the customers in Denmark:

IEnumerable<Order> orders = 
               Customers.Where(c => c.Country == "Denmark")
                         .SelectMany(c => c.Orders);

The following example creates a sequence of objects containing the customer name and order ID of the orders placed in 2005 by customers in Denmark:

var namesAndOrderIDs =
               Customers.Where(c => c.Country == "Denmark")                                .
                        .SelectMany(c => c.Orders)
                        .Where(o => o.OrderDate.Year == 2005)
                        .Select(o => new { o.Customer.Name, o.OrderID });

If an order had no Customer property (unidirectional relationship ), the query can be built keeping the current customer in scope such that it can be referenced in the final Select:

var namesAndOrderIDs =
              Customers.Where(c => c.Country == "Denmark")
                       .SelectMany(c => c.Orders, (c,o) => new { c, o })
                       .Where(co => co.o.OrderDate.Year == 2005)
                       .Select(co => new { co.c.Name, co.o.OrderID });
Filtering Operators
How to do it
// Filters a sequence of values based on a predicate 

public static IEnumerable<TSource> Where<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate
)

// Filters a sequence of values based on a predicate. Each element's index is used in the logic of the predicate function 

public static IEnumerable<TSource> Where<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, int, bool> predicate
)

// Filters the elements of an IEnumerable based on a specified type

public static IEnumerable<TResult> OfType<TResult>(
        this IEnumerable source
)
Partitioning Operators
How to do it
// Returns a specified number of contiguous elements from the start of a sequence 

public static IEnumerable<TSource> Take<TSource>(
        this IEnumerable<TSource> source,
        int count
)

// Returns elements from a sequence as long as a specified condition is true

public static IEnumerable<TSource> TakeWhile<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate
)

// Returns elements from a sequence as long as a specified condition is true. The element's index is used in the logic of the predicate function 

public static IEnumerable<TSource> TakeWhile<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, int, bool> predicate
)

// Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements 

public static IEnumerable<TSource> SkipWhile<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate
)

// Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements. The element's index is used in the logic of the predicate function

public static IEnumerable<TSource> SkipWhile<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, int, bool> predicate
)

// Bypasses a specified number of elements in a sequence and then returns the remaining elements 

public static IEnumerable<TSource> Skip<TSource>(
        this IEnumerable<TSource> source,
        int count
)
Element Operators
Remarks

Default value returned will be NULL for reference types and DEFAULT(Type) for value types

How to do it
// Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence

public static TSource Single<TSource>(
        this IEnumerable<TSource> source
)

// Returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists 

public static TSource Single<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate
)

// 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

public static TSource SingleOrDefault<TSource>(
        this IEnumerable<TSource> source
)

// Returns the only element of a sequence that satisfies a specified condition or a default value if no such element exists; this method throws an exception if more than one element satisfies the condition

public static TSource SingleOrDefault<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate
)

// Returns the last element of a sequence

public static TSource Last<TSource>(
        this IEnumerable<TSource> source
)

// Returns the last element of a sequence that satisfies a specified condition 

public static TSource Last<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate
)

// Returns the last element of a sequence, or a default value if the sequence contains no elements

public static TSource LastOrDefault<TSource>(
        this IEnumerable<TSource> source
)

// Returns the last element of a sequence that satisfies a condition or a default value if no such element is found 

public static TSource LastOrDefault<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate
)

// Returns the first element of a sequence 

public static TSource First<TSource>(
        this IEnumerable<TSource> source
)

// Returns the first element in a sequence that satisfies a specified condition

public static TSource First<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate
)

// Returns the first element of a sequence, or a default value if the sequence contains no elements 

public static TSource FirstOrDefault<TSource>(
        this IEnumerable<TSource> source
)

// Returns the first element of the sequence that satisfies a condition or a default value if no such element is found. 

public static TSource FirstOrDefault<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate
)
Sorting Operators
How to do it
// Sorts the elements of a sequence in ascending order according to a key 

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector
)

// Sorts the elements of a sequence in ascending order by using a specified comparer  

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector,
        IComparer<TKey> comparer
)

// Same as IEnumerable::OrderBy

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector
)
Set Operators
Remarks

If not parameterized the default equality comparer is used to compare values

How to do it
// Returns distinct elements from a sequence by using a specified IEqualityComparer<T> to compare values

public static IEnumerable<TSource> Distinct<TSource>(
        this IEnumerable<TSource> source,
        IEqualityComparer<TSource> comparer
)
Quantification Operators
How to do it
// Determines whether all elements of a sequence satisfy a condition/predicate

public static bool All<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate
)

// Determines whether any element of a sequence satisfies a condition/predicate

public static bool Any<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate
)

// Returns a number that represents how many elements in the specified sequence satisfy a condition/predicate
public static int Count<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate
)
Aggregation Operators
How to do it
// Applies an accumulator function over a sequence. The specified seed value is used as the initial accumulator value, and the specified function is used to select the result value 

public static TResult Aggregate<TSource, TAccumulate, TResult>(
        this IEnumerable<TSource> source,
        TAccumulate seed,
        Func<TAccumulate, TSource, TAccumulate> func,
        Func<TAccumulate, TResult> resultSelector
)

// Computes the sum of a sequence of values of value type <TResult>.

public static TResult Sum<TSource>(this IEnumerable<TSource> source)

// Computes the sum of the sequence of values of value type <TResult> that are obtained by invoking a transform function on each element of the input sequence

public static TResult Sum<TSource>(
	this IEnumerable<TSource> source,
	Func<TSource, TResult> selector
)

// Returns the maximum value in a sequence of values of value type <TResult>

public static TResult Max(this IEnumerable<TResult> source)

// Invokes a transform function on each element of a sequence and returns the maximum value of value type <TResult>

public static TResult Max<TSource>(
	this IEnumerable<TSource> source,
	Func<TSource, TResult> selector
)

// Returns the minimum value in a sequence of values of value type <TResult>

public static TResult Min(this IEnumerable<TResult> source)

// Invokes a transform function on each element of a sequence and returns the minimum value of value type <TResult>

public static TResult Min<TSource>(
	this IEnumerable<TSource> source,
	Func<TSource, TResult> selector
)

// Computes the average of a sequence of values of value type <TResult>.

public static TResult Average<TSource>(this IEnumerable<TSource> source)

// Computes the average of a sequence of values of value type <TResult> that are obtained by invoking a transform function on each element of the input sequence

public static TResult Average<TSource>(
	this IEnumerable<TSource> source,
	Func<TSource, TResult> selector
)
Grouping Operators
Remarks

If not parameterized the default equality comparer is used to compare keys.

How to do it
// Groups the elements of a sequence according to a specified key selector function and projects the elements for each group by using a specified function.

public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector,
        Func<TSource, TElement> elementSelector,
	IEqualityComparer<TKey> comparer
)
Join Operators
Remarks

If not parameterized the default equality comparer is used to compare keys.

How to do it
// Correlates the elements of two sequences based on matching keys

public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
        this IEnumerable<TOuter> outer,
        IEnumerable<TInner> inner,
        Func<TOuter, TKey> outerKeySelector,
        Func<TInner, TKey> innerKeySelector,
        Func<TOuter, TInner, TResult> resultSelector,
     IEqualityComparer<TKey> comparer
)

// Correlates the elements of two sequences based on equality of keys and groups the results
// The result selector function creates a result set from an element from the first sequence and a collection of matching elements from the second sequence

public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(
        this IEnumerable<TOuter> outer,
        IEnumerable<TInner> inner,
        Func<TOuter, TKey> outerKeySelector,
        Func<TInner, TKey> innerKeySelector,
        Func<TOuter, IEnumerable<TInner>, TResult> resultSelector,
     IEqualityComparer<TKey> comparer
)
Conversion Operators
Remarks

An exception is thrown if exists an element for each the cast operation fails: Use ::OfType() method instead.

How to do it
// Converts the elements of an IEnumerable to the specified type

public static IEnumerable<TResult> Cast<TResult>(
        this IEnumerable source
)

// Creates an array from a IEnumerable<T> 

public static TSource[] ToArray<TSource>(
        this IEnumerable<TSource> source
)

// Creates a List<T> from an IEnumerable<T>

public static List<TSource> ToList<TSource>(
        this IEnumerable<TSource> source
)

// Creates a Dictionary<TKey, TValue> from an IEnumerable<T> according to a specified key selector function. 

public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector
)

// Converts a generic IEnumerable<T> to a generic IQueryable<T> 

public static IQueryable<TElement> AsQueryable<TElement>(
        this IEnumerable<TElement> source
)
Equality Operators
How to do it
// Determines whether two sequences are equal by comparing their elements by using a specified IEqualityComparer<T> 

public static bool SequenceEqual<TSource>(
        this IEnumerable<TSource> first,
        IEnumerable<TSource> second,
        IEqualityComparer<TSource> comparer
)
Concatenation operators
Remarks

Alternatively concatenation of projection can be done

How to do it
// Concatenates two sequences 

public static IEnumerable<TSource> Concat<TSource>(
        this IEnumerable<TSource> first,
        IEnumerable<TSource> second
)
Generational Operators
Remarks

In case of a range the sequence can be changed by creating a projection over the generated values.

How to do it
// Returns an empty IEnumerable<T> that has the specified type argument

public static IEnumerable<TResult> Empty<TResult>();

// Generates a sequence of integral numbers within a specified range

public static IEnumerable<int> Range(
	int start,
	int count
)