The World’s Leading Microsoft .NET Magazine
   
 
The .NET Addict's Blog

My Top Tags

                                                           

My RSS Feeds








Latest Diggs - Programming

Internet Blogs - Blog Top Sites

Site Hits

Total: 2,551,710
since: 19 Jan 2005

The Adventures of LINQ (Not Zelda)

posted Fri 19 May 06

LINQ, which stands for Language Integrated Query, is almost like one of those trick hologram stickers like you used to get on the side of an ET happy mea..uh..I'm not that old, honest... Anyway, if you look at it from one angle, it seems to have one purpose and style, and if you look at it from another angle, it seems to have yet another purpose, style, and power.

LINQ combines the expressive nature and raw quering power of query languages like SQL with the familiarity, power, type-safety, and flexibility of the .NET Framework. LINQ comes in a couple different flavors (sadly, chocolate is not included):

  • LINQ, for working with in-memory objects such as strongly-typed lists, arrays, collections - basically anything that implements either IEnumerable or IEnumerable<T>
  • DLinq, for working with data. DLinq borrows the syntax and language extensions that are available with the core LINQ enhancements and uses them in combination with a powerful object-relational mapping mechanism to allow you to query the database directly from within your C# or VB.NET code - including identity management, updates, deletes, inserts, joins, full support for foreign keys, and much more.
  • XLinq - This is basically LINQ for use with XML queries and management.

As of the May CTP, LINQ can also be used to query DataSets ... but I haven't yet figured out a purpose for that, since the business objects that you get with SQLMetal, the OR/M code generator, are lighter weight, strongly-typed, and make heavy use of generics.

This blog entry wil introduce you to using LINQ with in-memory objects. The next blog entry will be about DLing, then I'll move on to XLinq after that.

Let's start with some simple in-memory data:

string[] names = {"Kevin", "Joe", "Bob", "Steve", "Al", "Rob", "Al", "DaVinci" };

In "legacy" C#, if you wanted to find all the names in this list that started with A, you'd have to write your own traversal. If you wanted to sort this array, you'd have to code your own custom IComparer function. There are a lot more things that people normally want to do against collections and lists that are, let's face it, a huge pain in the butt right now.

Not so with C# 3.0/LINQ. Take a look at this code:

var query = from name in names
  orderby name
descending
  select name.ToLower();

foreach (string modifiedName in query)
{
   Response.Write(modifiedName +
"<br/>"
);
}

The keyword var here instructs the compiler to infer the data type (do not confuse this with weak or late-bound typing, as it is neither. The type will be inferred from the type of the data that is first stored in the variable). Then we have a LINQ expression (see the documentation in the May CTP available from Microsoft for all the syntax rules) that queries the array of names, sorts the names in descending order, and then converts all the names to lower-case in the process and finally outputs all of that to a Web page.

The other feature of C# 3.0/LINQ that should not be overlooked is the use of lambda functions. Having spent a lot of time in college with Scheme and LISP, I went positively giddy when I found this.

You can define a lambda function that can then be passed to any function that can accept them, such as the where clause of a query. For every SQL-style keyword in C#, there is also an equivalent language extension method (such as .Where()) that can be invoked in a more C#-style means, as shown below with a Lambda function:

Func<string, bool> filter = s => s.Length > 3;

string[] names = {"Kevin", "Joe", "Bob", "Steve", "Al", "Rob", "Al", "DaVinci" };
IEnumerable<string
> expr =
  
from s in
names .Where(filter)
  
orderby s select s.ToUpper();

foreach (string item in expr)
{
    Response.Write(item +
"<Br/>"
);
}

This code will output all names that contain more than three characters, and it will output them in uppercase.

LINQ even supports grouping, as shown below in this code that groups names by their length and displays how many words there are of each length. One of the biggest problems that I have with grouping operators in traditional SQL, especially in SQL Server, is that once I group the results, I no longer have access to the individual details that supported the grouping. Not so with LINQ:

var wordGroups = from word in names
                          
group word by word.Length into
g
                          
select new { Length = g.Key, Words = g };

foreach (var wordGroup in wordGroups)
{
    Response.Write(
"Words that have " + wordGroup.Length.ToString() + " Letters:<br/>"
);

    foreach (var word in wordGroup.Words)
    {
        Response.Write(
"&nbsp;&nbsp;-" + word + "<Br/>"
);
    }
}

This produces the following output:

Words that have 5 Letters:
  -Kevin
  -Steve
Words that have 3 Letters:
  -Joe
  -Bob
  -Rob
Words that have 2 Letters:
  -Al
  -Al
Words that have 7 Letters:
  -DaVinci

This is just the tip of the iceberg. Whether you're writing a huge business application or whether you're writing a little helper app - the ability to use LINQ to query in-memory structures is going to not only save us developers countless hours of wasted time iterating through garbage and creating temp tables and all other manner of hacks and kludges, it will make the code easier to read, easier to maintain, and its just plain cool!

tags:          

links: digg this    del.icio.us    technorati    reddit




Tag Related Posts

MobileMe vs. Live Mesh Throwdown - Round 1

Wed 16 Jul 08 10:33 A GMT-05

Building Model Classes in C# and Cocoa

Sun 15 Jun 08 3:13 P GMT-05
tags:            

NYC SharePoint Developer Needed

Mon 12 May 08 12:09 P GMT-05

CLINQ v1.1.0.0 Released!

Fri 02 May 08 5:38 P GMT-05
tags:          

One Framework to Rule them All

Mon 25 Feb 08 6:49 P GMT-05

LINQ to REST - A much better name for Astoria

Tue 11 Dec 07 1:23 P GMT-05
tags:        

Unexpected and Unsafe behavior in LINQ

Wed 14 Nov 07 8:09 P GMT-05
tags:    

Continuous LINQ - Can I write games with it?

Mon 13 Aug 07 3:09 P GMT-05
tags:        

Continuous LINQ

Mon 06 Aug 07 1:21 P GMT-05
tags:    

Dynamic, Observable LINQ Views

Tue 31 Jul 07 1:21 A GMT-05
tags:        

The dreaded language bleed-over has begun

Tue 19 Jun 07 6:23 P GMT-05
tags:        

Installing Orcas Beta 1 - VMware Style

Mon 23 Apr 07 12:16 P GMT-05

Core Data - Almost too Easy?

Wed 18 Apr 07 2:23 P GMT-05

Will Silverlight be DOA?

Mon 16 Apr 07 8:02 P GMT-05

My Little Pony .NET Unleashed 2007

Fri 30 Mar 07 1:59 P GMT-05

An experience with the Leopard beta

Mon 26 Mar 07 7:45 P GMT-05
tags:                

Authorness

Thu 15 Mar 07 1:44 P GMT-05

Visual Studio "Orcas" - March CTP is Available

Wed 28 Feb 07 12:28 P GMT-05
tags:            

Objective-C Categories vs C# 3.5 Language Extensions

Mon 26 Feb 07 1:05 P GMT-05
tags:                

ASP.NET vs Ruby on Rails : Round 2 (Agility)

Thu 05 Oct 06 11:02 A GMT-05
tags:                      

ASP.NET vs Ruby on Rails : Round 1

Wed 04 Oct 06 1:37 P GMT-05
tags:                

First Impressions of Windows Vista RC1

Thu 07 Sep 06 1:30 P GMT-05
tags:                      

Localizing a WPF Application

Tue 22 Aug 06 11:39 A GMT-05
tags:            

WPF Slide Show and Photo Album

Fri 18 Aug 06 6:48 P GMT-05

Is Windows Workflow Foundation Too Complex?

Fri 18 Aug 06 12:15 P GMT-05

DLinq vs the ADO.NET Entity Framework

Fri 23 Jun 06 4:01 P GMT-05

WPF/XAML and LINQ - A match made in heaven

Tue 06 Jun 06 11:32 A GMT-05
tags:                  

Language Extensions in C# 3.0

Wed 31 May 06 2:17 P GMT-05

Lambda Lambda Lambda

Sun 21 May 06 1:01 A GMT-05