logo

C# - Chaining LINQ Queries Together

One of the cool things I discovered while getting to grips with LINQ is that you can chain LINQ queries together. This helps when trying to follow the Don't Repeat Yourself (DRY) approach to design, which I'm sure we all do.

While using DataSets and SQL/Stored Procedures in ASP.NET projects I was finding myself repeating the same SQL over and over. Any change to the column in any of the tables would likely mean a change to all the queries I had stored. Ergh.

As an example, let's say you have your zoo and its animals. If you want a list of animals that are viewable by the visiting public you might have a query like this:

public IEnumerable<Animal> GetViewableAnimals()
{
    return zoo.Animals.Where(
               a => a.Alive 
               && !a.Sick 
               && a.DepartureDate == null
         ).OrderBy(a => a.Name);
}

Not a great real-world example, but you get the idea - there's a base logic for what set of animals any other list should ever derive from.

Now, let's say you want get animals of a certain types (monkeys?). You might write another method, like so:

public IEnumerable<Animal> GetAnimalsByType(AnimalType type)
{
        return zoo.Animals.Where(
                a => a.Alive
                && !a.Sick
                && a.DepartureDate == null
                && a.Type = (int)type
        ).OrderBy(a => a.Name);
}

But, wait. You've repeated yourself! What if the logic by which you decide if an animal is "viewable" changes (say, you let the public see sick animals)!? You need to update all methods.

Well, you could instead have each method return an IQueryable object and chain them together. Like so:

public IQueryable<Animal> GetAnimalsByType(AnimalType type)
{
    return GetViewableAnimals()
                      .Where(a => a.Type == (int)type)
                      .OrderBy(a => a.DateOfBirth);
}
    
public IQueryable<Animal> GetViewableAnimals()
{
    return zoo.Animals.Where(
                a => a.Alive 
                && !a.Sick 
                && a.DepartureDate == null
          ).OrderBy(a => a.Name);
}

Notice how the "by type" method first gets the "base" query from the other method and then appends an extra clause to the "where" part of the statement.

Note that it's not until you try to access the data in the IQueryable class that it performs the SQL query. So, the above does not perform two SQL queries. Just one!

A fuller example would be the following example of a repository class:

public class AnimalRepository
{
    ZooDataClasesContext zoo = new ZooDataClasesContext();

    public IQueryable<Animal> Search(string query)
    {
        return GetViewableAnimals()
                .Where(a => a.Name.Contains(query))
                .OrderBy(a => a.Name);
    }
    
    public IQueryable<Animal> GetAnimalsByType(Animal.Type type)
    {
        return GetViewableAnimals()
                .Where(a => a.type == (int)type)
                .OrderBy(a => a.DateOfBirth);
    }

    public IQueryable<Animal> GetAnimalsByName(string name)
    {
        return GetViewableAnimals()
                .Where(a => a.Name == name)
                .OrderBy(m => m.DateOfBirth);
    }
    
    public IQueryable<Animal> GetAnimalsByType(AnimalType type)
    {
        return GetViewableAnimals()
                .Where(a => a.Type == (int)type)
                .OrderBy(a => a.DateOfBirth);
    }
    
    public IQueryable<Animal> GetViewableAnimals()
    {
        return zoo.Animals.Where(
                    a => a.Alive 
                    && !a.Sick 
                    && a.DepartureDate == null
                ).OrderBy(a => a.Name);
    }
}

There might be other or better ways to do this, but, for now, it's my preferred approach. I came up with the above while working on an app that has a fairly complex set of rules about what the base set of viewable rows are for the current user. Chaining queries like this means I only have to write this logic once.

Comments

  1. Sweeet. Jake - you've made the light go on for me with this! My mind is abuzz now and I'm thoroughly distracted from the Domino work I'm supposed to be doing. I'll have the client forward the tab to you for lost productivity. ;-)

      • avatar
      • Jake Howlett
      • Mon 7 Mar 2011 09:24 AM

      I'm doing Domino ("classic" !) work this week. It's hard to stay focused when I know what else I *could* be doing.

      But, yeah. Once the light lights up there's no end to what you can do. I'm constantly thinking of improvements to my working practice. I love it.

  2. Some more reading if you're interested:

    http://daniel.wertheim.se/2011/02/07/c-clean-up-your-linq-queries-and-lambda-expressions/

    Saves updating your query criteria in multiple places if the business changes their mind about what constitutes a viewable animal etc. (maybe the zoo goes into taxidermy or something? :D).

      • avatar
      • Jake Howlett
      • Tue 8 Mar 2011 01:08 AM

      Definitely interested. He's now in my RSS reader and on my twitter.

      I have an insatiable thirst for all things C# at the moment.

      Show the rest of this thread

  3. Great example. I'm distracted just like Jerry :-)

    • avatar
    • CJ
    • Mon 14 Mar 2011 04:57 AM

    If you're writing Linq queries you might want to check out LinqPad (http://www.linqpad.net). It's like SQL server management studio but lets you mess around with Linq (amongst others) instead.

  4. It took me awhile to move away from ADO but I'm amazed how at how

    linq continue to unfold, there are so many cool time savers poppin up. Your doing something that would take you 200 lines in ado in LINQ as an AT in one line F@ckin Ridiculous !

    @CJ Linq Pad is Cool ! I don't use SSMS anymore lol.

    • avatar
    • JiaJi
    • Wed 22 Jun 2011 07:20 PM

    Can I ask whether there is a way to use Linq to connect to Domino Web Source? thanks heps

Your Comments

Name:
E-mail:
(optional)
Website:
(optional)
Comment:


About This Page

Written by Jake Howlett on Mon 7 Mar 2011

Share This Page

# ( ) '

Comments

The most recent comments added:

Skip to the comments or add your own.

You can subscribe to an individual RSS feed of comments on this entry.

Let's Get Social


About This Website

CodeStore is all about web development. Concentrating on Lotus Domino, ASP.NET, Flex, SharePoint and all things internet.

Your host is Jake Howlett who runs his own web development company called Rockall Design and is always on the lookout for new and interesting work to do.

You can find me on Twitter and on Linked In.

Read more about this site »

More Content