Chapter 9. Querying and Manipulating Data with LINQ

This chapter is about Language Integrated Query (LINQ), a set of language extensions that add the ability to work with sequences of items and then filter, sort, and project them into different outputs.

This chapter covers the following topics:

  • Writing LINQ queries
  • Working with sets
  • Projecting entities with Select
  • Sweetening the syntax with syntactic sugar
  • Using multiple threads with parallel LINQ
  • Creating your own LINQ extension methods
  • Working with LINQ to XML

Writing LINQ queries

Although we wrote a few LINQ queries in Chapter 8, Working with Databases Using the Entity Framework Core, I didn't properly explain how LINQ works.

LINQ has several parts; some are required and some are optional:

  • Extension methods (required): These include examples like Where, OrderBy, Select, and so on. These are what provide the functionality of LINQ.
  • LINQ providers (required): These include LINQ to Objects, LINQ to Entities, LINQ to XML, LINQ to OData, LINQ to Amazon, and so on are LINQ providers. These are what convert standard LINQ operations into specific commands for different types of data.
  • Lambda expressions (optional): These can be used instead of named methods to simplify LINQ extension method calls.
  • LINQ query comprehension syntax (optional): These include from, in, where, orderby, descending, select, and so on. These are C# keywords that are an alias for some of the LINQ extension methods, and their use can simplify the queries you write, especially if you already have experience with other query languages, such as Structured Query Language (SQL).

Note

When programmers are first introduced to LINQ, they often believe that the query comprehension syntax is LINQ but, ironically, that is one of the parts of LINQ that is optional!

Extending sequences with the enumerable class

The extension methods, such as Where and Select, are appended by the Enumerable static class to any type, known as a sequence, that implements IEnumerable<T>.

For example, an array of any type automatically implements the IEnumerable<T> class, where T is the type of item in the array, so all arrays support LINQ to query and manipulate them.

All generic collections, such as List<T>, Dictionary<TKey, TValue>, Stack<T>, and Queue<T>, implement IEnumerable<T> so they can be queried and manipulated with LINQ.

Filtering entities with Where

The most common reason for using LINQ is to filter items in a sequence using the Where extension method.

In Visual Studio 2017, press Ctrl + Shift + N or navigate to File | New | Project.... In the New Project dialog, in the Installed | Templates list, expand Visual C#, and select .NET Core. In the list at the center, select Console App (.NET Core), type the name Ch09_LinqToObjects, change the location to C:Code, type the solution name Chapter09, and then click on OK.

In Visual Studio Code, make a directory named Chapter09 with a subfolder named Ch09_LinqToObjects. Open the Ch09_LinqToObjects folder and execute the dotnet new console command in the Terminal.

In the Main method, add the following statements:

    var names = new string[] { "Michael", "Pam", "Jim",  
      "Dwight", "Angela", "Kevin", "Toby", "Creed" }; 
    var query = names.Where( 

As you type the Where method, note that it is missing from the IntelliSense list of members of a string array, as shown in the following screenshot:

Filtering entities with Where

This is because the Where method is an extension method. It does not exist on the array type. It exists in a separate assembly and namespace. To make the Where extension method available, we must import the System.Linq namespace.

Add the following statement to the top of the Program.cs file:

    using System.Linq; 

Now, as you type the open parenthesis after Where, note the IntelliSense. It tells us that to call Where, we must pass in an instance of a Func<string, bool> delegate. This delegate must target a method with a matching signature:

Filtering entities with Where

Enter the following code to create a new delegate instance:

    var query = names.Where(new Func<string, bool>()) 

Note the IntelliSense shown in Visual Studio 2017 (but not in Visual Studio Code). This tells us that the target method must have a single input parameter of type string, and a return of type bool, as shown in the following screenshot:

Filtering entities with Where

For each string variable passed to the method, the method must return a Boolean value. If the method returns true, it indicates that we should include the string in the results, and if the method returns false, it indicates that we should exclude it.

Targeting a named method

Let's define a method that only includes names that are longer than four characters.

Add the following method under the Main method:

    static bool NameLongerThanFour(string name) 
    { 
      return name.Length > 4; 
    } 

Modify the Where call and loop through the query items, as shown in the following code:

    var query = names.Where( 
      new Func<string, bool>(NameLongerThanFour)); 
    foreach (var item in query) 
    { 
      WriteLine(item); 
    } 

In Visual Studio 2017, run the console application by pressing Ctrl + F5.

In Visual Studio Code, run the console application by entering dotnet run.

View the following output:

Michael
Dwight
Angela
Kevin
Creed

Simplifying the code by removing the explicit delegate instantiation

We can simplify the code by deleting the explicit instantiation of the Func<string, bool> delegate. The C# compiler will instantiate the Func<string, bool> delegate for us, so you never need to explicitly do it.

Modify the query to look like this:

    var query = names.Where(NameLongerThanFour); 

Rerun the application and note that it has the same behavior.

Targeting a lambda expression

We can simplify our code even further using a lambda expression in place of the named method.

Although it can look complicated at first, a lambda expression is simply a nameless function. It uses the => (read as "goes to") symbol to indicate the return value.

Modify the query to look like the following statement:

    var query = names.Where(name => name.Length > 4); 

Note that the syntax for a lambda expression includes all the important parts of the NameLongerThanFour method, but nothing more. A lambda expression only needs to define the following:

  • The names of input parameters
  • A return value expression

The type of the name input parameter is inferred from the fact that the sequence contains string values, and the return type must be a bool value for Where to work, so the expression after the => symbol must return a bool value.

The compiler does most of the work for us, so our code can be as concise as possible.

Rerun the application and note that it has the same behavior.

Sorting entities with OrderBy

Where is just one of about 30 extension methods provided by the Enumerable type. Extension methods can be chained if the previous method returns another sequence, that is, a type that implements the IEnumerable<T> class.

Append a call to OrderBy to the end of the existing query, as shown here:

    var query = names 
      .Where(name => name.Length > 4) 
      .OrderBy(name => name.Length);

Tip

Good Practice

Format the LINQ statement so that each extension method call happens on its own line to make them easier to read.

Rerun the application and note that the names are now sorted with shortest first:

Kevin
Creed
Dwight
Angela
Michael

Note

To put the longest name first, you will use OrderByDescending.

Sorting by multiple properties with the ThenBy method

We might want to sort by more than one property.

Append a call to ThenBy to the end of the existing query, as shown here:

    var query = names 
      .Where(name => name.Length > 4) 
      .OrderBy(name => name.Length) 
      .ThenBy(name => name);

Rerun the application and note the slight difference in the following sort order. Within a group of names of the same length, the names are sorted alphabetically by the full value of the string, so Creed comes before Kevin, and Angela comes before Dwight:

Creed
Kevin
Angela
Dwight
Michael
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.225.55.193