About

LINQ stands for Language Integrated Query.

It is a .Net query language used against strongly-typed objects.

To use LINQ in C#:

using System.Linq;

LINQ queries are strongly-typed.

LINQ to Objects let you run queries against IEnumerables. It is a declarative language that is easier to read/write than the nested foreach loops it replaces.

Deferred Execution

LINQ builds up a query, and does not actually execute it until you run an operation that requires it.


using System.Linq;

var list = from x in fullList where x.Property < 5 select x; 
//query has not been run yet

int count = list.Count(); 
//query was run so that count could be performed


LINQ To Objects

Comprehension Query Syntax

Basic example:

var query = from x in _db.Table 
            where x.Property < 5 
            orderby x.Name ascending
            select x;

Projection example:

var query = from x in _db.Table 
            where x.Property < 5 
            orderby x.Name ascending
            select new Result() {
                Id = x.Id,
                Name = x.Name,
                CountInstances = x.Instances.Count()
            };

Method Syntax

Method syntax makes use of Extension Methods and Lambda Expression.
Method syntax is also called Fluent syntax.

var query = _db.Table
            .Where(x => x.Property < 5)
            .OrderBy(x => x.Name)
            .Take(10);

The method syntax uses Method Chaining to combine as many query clauses as you need.

List<Part> parts = new List<Part>() { partA, partB... };

IQueryable<Part> list = parts.Skip(10);
list = list.Take(4).OrderBy(x => x.PartNumber);

Method Chaining means that each method returns the object the method is a part of, allowing you to immediately call another method on that object.


public class MethodChaining
{
    private int sum = 0;
    public MethodChaining Add(int x)
    {
        sum += x;
        return this;
    }
    public MethodChaining Substract(int x)
    {
        sum -= x;
        return this;
    }
}
...
MethodChaining methodChaining = new MethodChaining();
methodChaining.Add(5).Add(3).Subtract(4).Add(9);

Custom Functions

You can use Extension Methods to create your own custom LINQ clauses.


public static class LINQExtensions
{
    public static IEnumerable<T> Alternates(this IEnumerable<T> query)
    {
        List<T> alternates = new List<T>();
        for(int i=0; i<query.Count(); i+=2)
        {
            alternates.Add(query.ElementAt(i));
        }
        return alternates;
    }
}


public static class LINQExtensions
{
    public static double Median(this IEnumerable<double> query)
    {
        int count = query.Count();
        if(count == 0) throw new InvalidOperationException("Set is empty");

        query = query.OrderBy(x => x);
        int midIndex = (int)(count / 2);
        if(count % 2 == 0)
        {
            return (query.ElementAt(midIndex) + query.ElementAt(midIndex-1)) / 2;
        }
        else
        {
            return query.ElementAt(midIndex);
        }
    }
}

Query Syntax


List<Part> parts = new List<Part>() { partA, partB... };

var subList = from x in parts select x;

Part[] subList = (from x in parts select x).ToArray();


var subList = from x in parts where x.Name.StartsWith("R") select x;

OrderBy

var subList = from x in parts orderby x.PartNumber ascending select x;

Select

var subList = from x in parts select new { Number = x.PartNumber, WeightLbs = x.Ounces/16 };

Group

var byLastName = 
    from s in students
    group s by s.LastName into newGroup
    orderby newGroup.Key
    select newGroup;

foreach(var nameGroup in byLastName)
{
    Console.WriteLine("Group key = {0}", nameGroup.Key);
    foreach(var student in nameGroup)
    {
        Console.WriteLine("Group member = {0}", student.Name);
    }
}


LINQ To Object Methods

First

Returns the first element. Throws an exception if the enumerable if empty. Optional lambda.

Student student = students.First();
Student student = students.First(x => x.LastName == "Roberts");

Returns the first element. Returns the default type value if the enumerable is empty. Optional lambda.
(For reference types, NULL is default. For value types, 0 is default.)

Student student = students.FirstOrDefault();
Student student = students.FirstOrDefault(x => x.LastName == "Roberts");

Last

Returns the last element. Throws an exception if the enumerable is empty. Optional lambda.

Student student = students.Last();
Student student = students.Last(x => x.LastName == "Roberts");

Returns the last element. Returns the default type value if the enumerable is empty. Optional lambda.
(For reference types, NULL is default. For value types, 0 is default.)

Student student = students.LastOrDefault();
Student student = students.LastOrDefault(x => x.LastName == "Roberts");

Single

Returns the only element in the enumerable. Throws an exception if the enumerable length is not exactly 1. Optional lambda.

Student student = students.Single();
Student student = students.Single(x => x.LastName == "Roberts");

Take

Keep the next N elements

IEnumerable<Student> students = students.Take(4);

TakeWhile

Keep all elements until the condition is false:

IEnumerable<Student> students = students.TakeWhile(x => x.Age >= 21);

Skip

Skip the next N elements

IEnumerable<Student> students = students.Skip(4);

SkipWhile

Skip all elements until the condition is false

IEnumerable<Student> students = students.SkipWhile(x => x.Age >= 21);

Select

Sets what type to return from the query.

IEnumerable<int> studentAges = students.Select(x => x.Age);

MyType[] results = students.Select(x => new MyType() {
        Name = x.Name,
        Age = x.Age
    }).ToArray();

You can return anonymous types.

var studentSummaries = students.Select(x => 
    new { LastName = x.LastName, BestGrade = x.Grades.Max() });

SelectMany

Flattened nested data.

Language[] languages = books.SelectMany(b => b.Titles).Select(t => t.Language).ToArray();

Distinct

Return just distinct elements.

IEnumerable<string> surNames = students.Select(x => x.LastName).Distinct();

GroupBy

Groups the elements by the selected property.
Returns an enumerable of objects. Each has a Key and is also an enumerable you can iterate over to see the elements in the group.

IEnumerable<IGrouping<string, Student>> studentGroups = students.GroupBy(x => x.LastName);

foreach(IGrouping<string, Student> group in studentGroups)
{
    Console.WriteLine("Group key = {0}", group.Key); //Key is the LastName
    foreach(Student student in group)
    {
        Console.WriteLine("Group member = {0}", student.FirstName);
    }
}

You can supply a custom comparer in GroupBy. Each pair of elements will be checked for equality with the custom comparer.

using System;
using System.Collections.Generic;
using System.Linq;

public class CustomComparer : IEqualityComparer<T>
{
    public bool Equals(T a, T b)
    {
        //return true if a and b should be considered equal
    }

    public int GetHashCode(T obj)
    {
        //return hashcode
    }
}

...myList.GroupBy(x => x, new CustomComparer());

OrderBy

Sort the elements by the specified value. Ascending order.

IEnumerable<Student> students = students.OrderBy(x => x.LastName);

Use a custom comparison function:

using System.Collections.Generic;

public class MyComparer : IComparer<MyType>
{
    public int Compare(MyType a, MyType b)
    {
        //return positive if "a" should be higher, return negative if "b" should be higher
    }
}

//to use it
var result = collection.OrderBy(x => x, new MyComparer())

OrderByDescending

Sort the elements by the specified value. Descending order.

IEnumerable<Student> students = students.OrderByDescending(x => x.LastName);

ThenBy

This will set the next level of sorting. Use after an OrderBy, OrderByDescending, ThenBy, or ThenByDescending clause. Ascending order.

IEnumerable<Student> students = students.OrderBy(x => x.LastName).ThenBy(x => x.FirstName);

ThenByDescending

This will set the next level of sorting. Use after an OrderBy, OrderByDescending, ThenBy, or ThenByDescending clause. Descending order.

IEnumerable<Student> students = students.OrderBy(x => x.LastName).ThenByDescending(x => x.Age);

Where

Filters elements by a conditional statement

IEnumerable<Student> students = students.Where(x => x.LastName == "Roberts");

OfType

Filters elements by their Type

IEnumerable<Student> students = people.OfType<Student>();

Union

Given two enumerables, returns the distinct elements of both enumerables together.

IEnumerable<int> luckyOrPrime = primeNumbers.Union(luckyNumbers);

You can also define what comparison function to use.

IEnumerable<int> luckyOrPrime = primeNumbers.Union(luckyNumbers, new IEqualityComparer<T>());

Count

Return the element count

int count = numbers.Count();

Average

Return the average of the values.

decimal averageNumber = numbers.Average();

decimal averageAge = students.Average(x => x.Age);

Sum

Returns the summation of the values.

int sumNumbers = numbers.Sum();

int sumAges = students.Sum(x => x.Age);

Any

Returns true if any element of the enumerable matches the condition:

bool includesAdults = students.Any(s => s.Age >= 18);

Join

Explicitly join objects, like a SQl table join.

var result = dbContext.TableA.Join(
    dbContext.TableB, 
    outer => outer.TableB.Column, 
    inner => inner.TableA.Column, 
    (outer, inner) => new { A = outer, B = inner}
);

Dictionary

Build a dictionary:

Dictionary<int, name> dict = list.ToDictionary(x => x.Id, x => x.Name);
LINQ To Entities

Method Syntax

(Method Syntax is also called Fluent Syntax)

LINQ to Entities includes all the LINQ to Objects Method Syntax options.


using (var context = new MyEntities())
{
    return context.Students.Where(x => x.LastName == "Roberts").FirstOrDefault();
}

Explicitly loading data when using lazy loading.


Student student = context.Students.Include("Classes").Include("History.PreviousSchools").FirstOrDefault();

Filtering by a subtype.


Student student = context.People.OfType<Student>().FirstOrDefault();

Query Syntax

LINQ to Entities includes all the LINQ to Objects Syntax Syntax options.


using (var context = new MyEntities())
{
    return (from student in context.Students where student.LastName == "Roberts" select student).First();
}

Entity SQL

You can also query the entities with a SQL-like language.


string queryString = "SELECT VALUE s FROM MyEntities.Students AS s WHERE s.LastName == 'Roberts'";
var objectContext = (context as IObjectContextAdapter).ObjectContext;
ObjectQuery<Student> students = objectContext.CreateQuery<Student>(queryString);

Native SQL


using (var context = new MyEntities())
{
    return context.Students.SqlQuery("SELECT Id, FirstName FROM Student WHERE LastName == 'Roberts'");
}


LINQ To SQL

todo
LINQ To XML

todo