Monday, November 8, 2010

LINQ Query Operators

Query operators such as SelectMany, Concat, Object Initializers, OrderBy,

AsEnumerable, defaultifempty and how to do left joins in LINQ to SQL.

Standard Query Operators

The list of standard query operators is huge. I will cover a few of them that I found interesting and that require a bit of understanding.

Select Many and Concat Operators

The SelectMany operator is used to create one to many projections. The SelectMany operator will return zero or more inputs for every input element. The prototype is as follows:

public static IEnumerable<s> SelectMany(

this IEnumerable source,

Func> selector);

The operator takes an input sequence of T and a selector delegate that takes an element of type T. It returns an IEnumerable of S, an intermediate output sequence. Let's see an example:

public static void SelectManyOperator()

{

string[] items = { "this", "is", "a", "test" };

IEnumerable characters = items.SelectMany(s => s.ToCharArray());

foreach (char character in characters)

{

Console.WriteLine(character);

}

}

public static void ConcatAndSelectManyOperator()

{

string[] books = {

"ASP.NET 2.0 Website Programming: Problem -

Design - Solution",

"Pro ASP.NET 3.5 in C# 2008, Second Edition",

"ASP.NET 2.0 Unleashed",

"ASP.NET 3.5 Unleashed "

};

IEnumerable concatbooks = books.Take(2).Concat(books.Skip(2));

IEnumerable selectmanybooks = new[]{

books.Take(2),

books.Skip(2)

}.SelectMany(b => b);

}

Using concat or selectmany would yield the same results, but the advantage of selectmany is that it allows you to merge more than two sequences to return a single sequence back.

Object Initializers

There is a C# language feature in the upcoming "Orcas" version known as object initializers. Object initializers basically allow the assignment of multiple properties or fields in a single expression. For example, a common pattern for object creation is:

Customer customer = new Customer();

customer.Name = “Roger”;

customer.Address = “1 Wilco Way”;

In this case, there is no constructor of Customer that takes a name and address; however, there are two properties, Name and Address, that can be set once an instance is created. Object initializers allow the same creation with the following syntax:

Customer customer = new Customer()

{ Name = “Roger”, Address = “1 Wilco Way” };

In our earlier CustomerTuple example, we created the CustomerTuple class by calling its constructor. We can achieve the same result via object initializers:

var locals =

customers

.Where(c => c.ZipCode == 91822)

.Select(c =>

new CustomerTuple { Name = c.Name, Address = c.Address });

Notice that object initializers allow the parentheses of the constructor to be omitted. In addition, both fields and settable properties can be assigned within the body of the object initializer.

We now have a succinct syntax for creating queries in C#. However, we also have an extensible way to add new operators (Distinct, OrderBy, Sum, and so on) through extension methods and a distinct set of language features useful in their own right.

The language design team now had several prototypes to get feedback on. So we organized a usability study with many participants who had experience with both C# and SQL. The feedback was almost universally positive, but it was clear there was something missing. In particular, it was difficult for the developers to apply their knowledge of SQL because the syntax we thought was ideal didn’t map very well to their domain expertise.

No comments: