Using Where Clauses with LINQ in VB

Introduction

I have a good understanding of XML, but don't use XPath that often. I can command write queries against Active Directory, but have to look up the syntax because I do it infrequently. I have been using SQL in its various forms for more than a decade, so writing SQL queries, except in a few cases is something I can do adroitly. And, when it comes to querying objects in code I have the most experience, having re-written dozens of algorithms long before they were part of the framework. All of these conflicting skill sets represent part of the problem: programming today has up until now required too many disparate skill sets. Having to focus on how to accomplish something and not just expressing a solution makes querying data much harder than it should be. Enter LINQ.

Only a few times in the past--when I did a stint with Microsoft Consulting--have I been part of the internal discussions for Microsoft technologies, discussions about the motivation behind creating a new technology. Unfortunately, besides from very helpful discussions with people like Tim Ng and Charlie Calvert, I wasn't privy to the early discussions about LINQ. One can make a reasonable guess though-too many ways to query data, too many skill sets, and too much inconsistency. LINQ was invented to make it easier to express what you want to accomplish and less on how or the underlying technology.

The result is LINQ. LINQ in its simplest form is basically very similar to an inverted SQL query--with select coming last--but there are several intricacies that it is helpful to know about. In this article I am focusing on the WHERE clause, including how it evolved and how you can apply it in LINQ queries.

Understanding the Origins of the Where Clause

Interfaces like IEnumerable and IEnumerable(Of T) are sealed interfaces, and generally interfaces aren't suppose to change because any change would be a breaking change. As a solution extension methods were invented (or introduced into .NET). There are some 1,000 programming languages, so extension methods may have been introduced in some earlier language like Modula-2, LOOPS, Flavors, or SmallTalk but .NET was where I first heard about them.

An extension method is basically a static method in a static class. The first argument defines the type being extended and the compiler resolves an extension method as if it were a member--of the type being extended. Extension methods in a nutshell are a way to extend an existing type without actually modifying that type. Extension methods are compiler-resolution magic.

The method Where was originally introduced as an extension method for types that implement IEnumerable(Of T), such as a collection or array of something. The basic Where extension method accepts a generic delegate or Lambda Expression--a short hand form of the delegate--with a generic input and a Boolean result. The second form accepts the input type, an integer representing the items index, and a Boolean. These can be expressed as an instance of the generic delegate Func(Of T, Boolean) or Func(Of T, Integer, Boolean). Listing 1 demonstrates the Where extension method using the generic delegate Func(Of T, Boolean).

  Sub Listing1()
        Dim numbers() As Integer = {1, 2, 3, 4, 5}
        Dim test As Func(Of Integer, Boolean) = _
          Function(i As Integer) i Mod 2 = 1
  
        Dim odds = numbers.Where(test)
  
        For Each num In odds
          Console.WriteLine(num)
        Next
        Console.ReadLine()


End Sub
Listing 1: Using the Where extension method with the generic delegate Func(Of T, Boolean).

In the example an array of integers is defined. Next, the generic delegate Func (Of Integer, Boolean) is assigned the Lambda expression Function (I as Integer) I Mod 2 = 1 followed by the Where extension method called on the array and the output sent to the console. It is worth noting that the Lambda expression could be used directly in the Where method (as shown in Listing 2).

  Sub Listing2()
        Dim numbers() As Integer = {1, 2, 3, 4, 5}
        Dim odds = numbers.Where(Function(i As Integer) i Mod 2 = 1)
  
        For Each num In odds
          Console.WriteLine(num)
        Next
        Console.ReadLine()
  
  
  End Sub
Listing 2: Code that behaves identically to Listing 1 with the Lambda expression used directly in the Where method.

Lambda expressions are simply short hand function notation, used for convenience in places like Where extension methods. For more on Lambda expressions see my book LINQ Unleashed for C# or Professional DevExpress ASP.NET Controls. Both books have several examples of LINQ expressions and a discussion of Lambda expressions (Both books are in C#; while the syntax is different the concepts are the same).

Using Where with a Single Predicate

In LINQ the Where clause uses a syntax similar to a SQL statement. When you write a Where clause in LINQ the compiler converts it to a Where extension method call. The argument or arguments to a Where clause have to evaluate to a Boolean expression and can be referred to as predicates or expressions (I will use either expression, based on which sounds the best in a particular sentence).

Where clauses can have a single predicate, multiple predicates formulated with a combination of And or Or operators, or multiple Where clauses. Listing 3 is a revision of Listing 2. Listing 3 converts the direct use of the Where extension method with its implicit use in a LINQ query.

  Sub Listing3()
        Dim numbers() As Integer = {1, 2, 3, 4, 5}
  
        Dim odds = From number In numbers _
                   Where number Mod 2 = 1 _
                   Select number
  
  
        For Each num In odds
          Console.WriteLine(num)
        Next
        Console.ReadLine()
  
  End Sub
Listing 3: A LINQ query that obtains the odd numbered integers.

In the example, the Where clause has a single predicate-number Mod 2 = 1. When the value in the query is odd it ends up in the result set.

I don't have a crystal ball, but I can guess what you might be thinking: numbers. Where is a lot shorter and simper than the LINQ query shown in Listing 3. In this instance you would be correct. The difficulty in writing lengthy queries using all extension methods is that the results become very challenging to read and write the more complex the queries get. Use LINQ and let the compiler code-generate the extension method calls.

Using Where Clauses with LINQ in VB

Using Where with Multiple Predicates

If you want more than a single kind of result use multiple sub-expressions. You can use And logic where all sub-expressions have to be true or use Or logic when only one expression has to be true for the whole result to evaluate to true. Listing 4 shows an And operator, and Listing 5 uses an Or operator.

  Sub Listing4()
        Dim numbers() As Integer = {1, 2, 3, 4, 5}
  
        Dim odds = From number In numbers _
                   Where number Mod 2 = 1 And _
                   number >= 3 _
                   Select number
  
  
        For Each num In odds
          Console.WriteLine(num)
        Next
        Console.ReadLine()
  End Sub
Listing 4: A LINQ query with two sub-expressions in the Where clause logically determined with an And operator.

  Sub Listing5()
        Dim numbers() As Integer = {1, 2, 3, 4, 5}
  
        Dim odds = From number In numbers _
                   Where number Mod 2 = 1 _
                   Or number = 4 _
                   Select number
  
        For Each num In odds
          Console.WriteLine(num)
        Next
        Console.ReadLine()
  End Sub
Listing 5: A LINQ query with two-subexpressions in the Where clause logically determined with an Or operator.

In Listing 4 the result set is 3 and 5-odds greater than 3. In Listing 5 the result is 1,3,4,5-odds and 4. You can daisy chain sub-expressions using And and Or logic in any way that you need but more than three or four sub-expressions and the logic condition will get very difficult to read. The study of logic is called discrete mathematics with the logic being explored as the propositional and predicate calculus. In practice it is a good idea to avoid very complex predicates; this holds true for all code including LINQ.

Using Multiple Where Clauses

You also have the option of using more than one Where clause. To use more than one Where clause just add additional Where clauses after the from and before the select. The reason for doing so has to do with short circuiting expensive conditional checks. I don't use this approach very often, but for expensive conditions like those that use IO multiple Where clauses can be helpful (For an example of multiple where clauses using File IO in the sub-expression see my blog post Using Multiple Where Clauses with LINQ.

Listing 6 contains multiple where clauses against the numbers array, though there is no practical justification for doing so (For another interesting use of multiple where clauses see Jerome Laban's blog post http://jaylee.org/post/2008/12/fsharp-TryWith- Maybe-and-Umbrella.aspx).

  Sub Listing6()
        Dim numbers() As Integer = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
  
        Dim odds = From number In numbers _
                   Where number Mod 2 = 1 _
                   Where number / 5 = 1 _
                   Select number
  
        For Each num In odds
          Console.WriteLine(num)
        Next
        Console.ReadLine()
  End Sub
Listing 6: Multiple where clauses are useful for short circuiting queries when it makes sense to do so; for instance when a secondary sub-expression may be expensive to evaluate.

The last result set is 5. This example shows you the syntax for multiple where clauses, but it could have been satisfied sufficiently with a single Where with two sub-expressions and an And operator.

Summary

How much work you have to do to solve a problem is a function of preparation. The more you know about a technology the quicker you will get to a solution in practice. You now have a better understanding of LINQ and Where clauses. Remember LINQ queries are converted into extension method calls, but writing LINQ queries lets you focus on a what you want less than the technical path to getting there.

About the Author

Paul Kimmel is the VB Today columnist for CodeGuru and has written several books on object-oriented programming and .NET. Check out his upcoming book Professional DevExpress ASP.NET Controls (from Wiley) now available on Amazon.com and fine bookstores everywhere. Look for his upcoming book Teach Yourself the ADO.NET Entity Framework in 24 Hours (from Sams). You may contact him for technology questions at pkimmel@softconcepts .com. Paul Kimmel is a Technical Evangelist for Developer Express, Inc, and you can ask him about Developer Express at paulk@devexpress.com and read his DX blog at http:// community.devexpress.com/blogs/paulk.



About the Author

Paul Kimmel

Paul Kimmel is the VB Today columnist for CodeGuru and has written several books on object-oriented programming and .NET. Check out his upcoming book Professional DevExpress ASP.NET Controls (from Wiley) now available on Amazon.com and fine bookstores everywhere. Look for his upcoming book Teach Yourself the ADO.NET Entity Framework in 24 Hours (from Sams). You may contact him for technology questions at pkimmel@softconcepts .com. Paul Kimmel is a Technical Evangelist for Developer Express, Inc, and you can ask him about Developer Express at paulk@devexpress.com and read his DX blog at http:// community.devexpress.com/blogs/paulk.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • On-demand Event Event Date: October 29, 2014 It's well understood how critical version control is for code. However, its importance to DevOps isn't always recognized. The 2014 DevOps Survey of Practice shows that one of the key predictors of DevOps success is putting all production environment artifacts into version control. In this webcast, Gene Kim discusses these survey findings and shares woeful tales of artifact management gone wrong! Gene also shares examples of how high-performing DevOps …

Most Popular Programming Stories

More for Developers

RSS Feeds