Mike Taulty's Blog
Bits and Bytes from Microsoft UK
TechEd Europe - Follow Up 1. In LINQ, "Where" == "AndWhere"
Mike Taulty's Blog

Mike's Badges

Follow on Twitter
View mike's profile on slideshare
Add to Technorati Favorites
CW Blog Awards

Someone at TechEd yesterday asked me a great question about LINQ which is something that I've puzzled about before (and I was pretty sure that I'd written it up on this website but I can't find it so hopefully I'm not duplicating myself).

Let's say we have a query like this;

var entries = new[] {
        new { Name = "Albert", Age = 10 },
        new { Name = "Brian", Age = 20 },
        new { Name = "Charlie", Age = 30 }
      };

      var query = from e in entries
                  where e.Age < 20
                  select e;

      query = from q in query
              where q.Age > 20
              select q;

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

 

What does this print out? Nothing. Why? Because the Where clause in LINQ is really a filter.

Now, I'm using an array of anonymous types as the source of my query here which means we have IEnumerable<ANON_TYPE> and so this is probably what you would expect. The first Where clause acts as a filter on the array and that produces one element where (Age = 10). We then take that filtered list and we apply a second filter to it looking for (Age > 20) and we therefore end up with an empty list.

Maybe it's more obvious if it's restated as this;

   static void Main(string[] args)
    {
      var entries = new[] {
        new { Name = "Albert", Age = 10 },
        new { Name = "Brian", Age = 20 },
        new { Name = "Charlie", Age = 30 }
      };

      var query = 
        entries.Where(e => e.Age < 20).Where(e => e.Age > 20).Select(e => e);

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

 

As it "looks" more obvious that here what happens is that we execute the first Where and then we execute the second Where.

Now, if we re-formulate this in the world of LINQ to SQL then (imho) this doesn't necessarily have to be the case although it is the case. Imagine (using LINQ to SQL) I have;

 static void Main(string[] args)
    {
      using (NorthwindDataContext ctx = new NorthwindDataContext())
      {
        var query = from c in ctx.Customers
                    where c.Country == "Germany"
                    select c;

        query = from q in query
                where q.Country == "Spain"
                select q;

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

Which produces no results either.

Now, a customer asked me yesterday;

How come this (effectively) produces the following

SELECT * FROM CUSTOMERS WHERE COUNTRY='Germany' AND COUNTRY='Spain'

rather than

SELECT * FROM CUSTOMERS WHERE COUNTRY='Germany' OR COUNTRY='Spain'

and (to me) it's because, whilst it would be possible to insert an OR clause in the case of an IQueryable implementation of LINQ such as LINQ to SQL it would not be possible to insert an OR clause in an IEnumerable implementation of LINQ and so you would lose consistency and things become messy.

Now, in order to preserve that consistency the query expression pattern doesn't do this but the LINQ to SQL API does. So, one way of doing it with LINQ to SQL is by doing something like;

 static void Main(string[] args)
    {
      using (NorthwindDataContext ctx = new NorthwindDataContext())
      {
        var query = from c in ctx.Customers
                    where c.Country == "Germany"
                    select c;

        query = from q in
                  query.Union(
                    from c in ctx.Customers
                    where c.Country == "Spain"
                    select c)
                select q;

        foreach (var item in query)
        {
          Console.WriteLine(item.CustomerID);
        }
      }
    }
and that gets you to where you want to be, albeit in a longer way around :-)
Posted Sat, Nov 10 2007 4:41 AM by mtaulty

Comments

Jason Haley wrote Interesting Finds: November 10, 2007
on Sat, Nov 10 2007 8:55 AM
Christopher Steen wrote Link Listing - November 10, 2007
on Sat, Nov 10 2007 9:17 PM
ASP.NET  The REST-Like Aspect Of ASP.NET MVC [Via: Haacked ] WPF  Routed Event Viewer [Via: Karl Shifflett...
Christopher Steen wrote Link Listing - November 10, 2007
on Sat, Nov 10 2007 9:17 PM
Link Listing - November 10, 2007
NBAVids - Basketball Rocks » TechEd Europe - Follow Up 1. In LINQ, "Where" == "AndWhere" wrote NBAVids - Basketball Rocks &raquo; TechEd Europe - Follow Up 1. In LINQ, &quot;Where&quot; == &quot;AndWhere&quot;
on Sun, Nov 18 2007 1:57 AM
Mike Taulty's Blog wrote Messing with Dynamic LINQ Queries
on Thu, Sep 11 2008 9:08 AM
Mike was chatting to me about how you'd take something like this ( against LINQ to SQL and the Northwind...
(C) Mike Taulty, 2009. All rights reserved. The information in this weblog is provided "AS IS" with no warranties, and confers no rights. This weblog does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion. Inappropriate comments will be deleted at the authors discretion. All code samples are provided "AS IS" without warranty of any kind, either express or implied, including but not limited to the implied warranties of merchantability and/or fitness for a particular purpose.
Powered by Community Server (Non-Commercial Edition), by Telligent Systems