Friday, 14 August 2015

Starting LINQ

Language Integrated Query was introduced in C# 3.0 and it allows you to query any collection - in memory, a database, etc with standard powerful logic / operators.  Historically developers had to learn multiple APIs to deal with data from different sources e.g. XML, database or in memory.  LINQ brings data access into the .Net languages (that support generics, specifically support IEnumerable<T>) and provides both intellisense and static type checking within the IDE.  These were lacking in previous data access coding APIs.   This one common way of accessing data (LINQ) is akin to the one common way of accessing external communications (WCF) which unified calls queues, web services, pipes, etc.

Out of the box LINQ provides approximately 50 standard query operators:-

  • Filtering (e.g. where)
  • Projection (e.g. select. Projection returns just some data attributes in an object/table, not all)
  • Joining
  • Partitioning (skip, take.  Useful for pagination e.g. give me results 11-20).
  • Ordering (order by)
  • Aggregating (group by)
Many of these are similar to SQL.

The same standard operators work everywhere.  There are additionally custom query operators / providers produced by the user community (e.g. LINQ to Amazon).

  • LINQ to SQL supports SQL Server only.  LINQ to entities provides ORM features.
  • LINQ to XML supports XML, with a new XML API (System.XML.Linq) that is less formal and easier to use.
  • LINQ to Objects supports working with objects in memory.  This is often overlooked but is very powerful, and can replace foreach loops and selections with much more succinct code.


You can return results as collections of anonymous classes.  There are two styles/syntaxes for writing LINQ queries, Method Syntax and Query Syntax.

Method Syntax

(Very like SQL, just with the select statement at the end of the expression)
var results = from x in staff where x.Grade = "Manager"
select new {x.Name, x.PhoneNumber}

Query Syntax


(Uses a lambda expression - input parameter(s) to an anonymous method that returns a result).
var results = staff.Where(x=>x.Grade=="Manager");


LINQ Query Operators

LINQ contains some familiar and some new (but very useful) operators:

orderby

This is the same as the SQL order by clause.

            var doubleQuery = from method in typeof(double).GetMethods()
                        orderby method.Name
                        group method by method.Name into groups
                        select new { MethodName = groups.Key, NumberOfOverLoads = groups.Count() };

            foreach (var item in doubleQuery)
            {
                Console.WriteLine(item);
            }
            Console.ReadLine();

group

Same as the SQL group by clause.  (See orderby example, above).

any

Returns true if a collection has any members.
var largeList = Enumerable.Range(1,20);
var largeListEmpty = largeList.Any();
Console.WriteLine("largeList contains items? " + largeListEmpty);

contains

Returns true if a collection contains the item(s) provided in the statement
Console.WriteLine("largeList contains 7? " + largeList.Contains(7));
Console.WriteLine("largeList contains 27? " + largeList.Contains(27));

take

Takes (copies) the first n items out of the collection.
var largeList = Enumerable.Range(1,20);
var smallList = largeList.Take(5).Select(x => x * 10);

foreach (var item in smallList)
{
    Console.WriteLine(item);
}


foreach (var item in largeList)
{
    Console.WriteLine(item);
} //largeList is unchanged as the items were copied out.

Take can be a useful way of limiting your result set.

zip

Zips together two collections (presumably they need to have a matching number of items).
string[] shortMonth = { "Jan", "Feb", "Mar", "Apr", "May" };
string[] longMonth = { "January", "February", "March", "April", "May" };

var monthMapping = shortMonth.Zip(longMonth, (sMonth, lMonth) => sMonth + ": " + lMonth);

foreach (var m in monthMapping)
{
     Console.WriteLine(m);
}
Console.ReadLine();

Deferred Execution

LINQ query expressions usually do not execute until we access the result, i.e. they are lazy operators.  (Certain LINQ operators such as count are greedy and execute immediately).  Thus you can build up queries as user input changes, and only execute it once, when needed.  In the order by example, above, the LINQ query only executes when the foreach loop calls it.  It is defined first but execution is deferred until needed.  This is not unlike deploying a stored procedure in a database that only executes when called.

Summary

LINQ allows you to query any collection using one standard API
LINQ standard operators work against IEnumerable<T>
It has many useful operators
It has a powerful chaining syntax to combine operators together powerfully.

No comments:

Post a Comment