Lesson 8 - LINQ providers, anonymous types, grouping and sorting in C#

C# .NET Collections and LINQ LINQ providers, anonymous types, grouping and sorting in C#

In the previous lesson, LINQ in C# - Revolution in querying, we introduced the LINQ technology and created our first simple query. In today's tutorial, we're going to continue working with LINQ.

Providers

We mentioned that LINQ works using providers. These are the implementations of the LINQ methods for different platforms so that we're able to call LINQ queries on them. Let's go over a few basic LINQ providers and talk a little bit about each one of them.

Providers in .NET:

Some providers are delivered by Microsoft directly from the .NET framework. We'll mainly be interested in the following:

  • LINQ to Objects - A provider that allows us to run queries on core collections. We used it last time for querying on an array, we can also execute queries on lists and other .NET collections. LINQ to Objects works with data in computer memory.
  • LINQ to SQL/LINQ to Entities - A provider mapping LINQ statements on SQL queries, which allows us to work with the MS-SQL database. They also give us ORM (Object-relation mapping, more on that in future lessons). Working with the database is then fully object-oriented. We'll work with Linq to Entities a lot in future courses, LINQ to SQL is more so its predecessor. LINQ to Entities is a part of the Entity framework which is a rather extensive library for working with relational (database) data.
  • LINQ to XML - A provider that enables queries over XML files. As with LINQ to Entities, we'll be able to use the object-oriented approach.

Third-party providers

Since we're able to create our own providers, it would only make sense that there are many third-party solutions out there. However, some of them might not be well supported and it's a very good idea to stick with Microsoft's technologies instead.

  • DbLinq - The most widely used third-party provider which allows us to use LINQ technology on MySQL, SQLite, Oracle, PostgreSQL, Firebird and other heavily used database platforms.
  • LINQ to Excel - This provider enables us to work with Excel spreadsheets (Excel document) just like a database.
  • LINQ to JSON - A provider for querying JSON files.
  • LINQ to Amazo - LINQ to Amazon is often cited as an example of a third-party provider. Using LINQ queries, we can search through the books which are offered by this online store.

As you can see, there are a lot of providers. Once we know how to use LINQ, we'll be able to use it on almost anything. For the time being, we'll focus on LINQ to XML and LINQ to Entities.

Anonymous types

To be able to create more complex queries, more precisely, to only get the part of the result we're interested in, we'll use anonymous types. An anonymous type behaves like an instance of a class, but without having to declare a class. Let's try it out:

var anonym = new { Name="Anonymous", Surname="Very anonymous", Age="18" };
Console.WriteLine(anonym.Name);
Console.WriteLine(anonym.Surname);
Console.WriteLine(anonym.Age);

The output is as follows:

Console application
Anonymous
Very anonymous
18

We created an anonymous data type that has three attributes. We put values into them and put the entire structure in a variable of the var type. The resulting data type is very strange and we would barely be able to declare it without the var keyword.

What is the advantage to having such data types? In our queries, we can map anything we want using the select clause. Let's make a quick collection of cars and drivers. We'll make it so we always pick the license plates for red cars along with the full names of the drivers. The drivers have FirstName and LastName properties. Independently from that, the car properties are Color, Driver, and LicencePlate. The query would look something like this:

var query = from c in cars
            where (c.Color == "red")
            select new { c.LicencePlate, DriverName = c.Driver.FirstName + " " + c.Driver.LastName };

The query could return a complex result such as this one, so we had to create an anonymous data type for it. The query result will be a collection of elements, where each element will have the LicencePlate and DriverName properties. Notice how we only wrote c.LicencePlace once and DriverName = ... once. If we wanted to add a pre-existing property with the same name, we would simply name it as such. If we wanted a property with a different name, we would have to use PropertyName = value.

Attention: Do not misuse anonymous types, just like one shouldn't misuse the var keyword. Again, it's a functionality created for specific purposes, mainly for LINQ queries.** Do not use anonymous types instead of classes in your regular programs, it would reduce the quality of both the source code and the resulting application. Attributes of anonymous types are read-only, more precisely, they're **properties. We usually avoid anonymous types and design the application layer in a way that doesn't require us to write queries that are too complex. By using anonymous types, we get rid of relationships between entities, which may result in a more complex application and in many other problems. The best solution for the situation shown above would be to create a DriverName property in the car class and then select an entire car simply using select a. We'd extract the driver's name from it later easily as with the anonymous type. We'd also be working with the entire car, including all of its relations and not with an unidentified anonymous entity. However, anonymous types have their place in complex queries. Especially, single-purpose queries, and will often appear in the sample queries in our courses.

We now know everything needed to get into the syntax for advanced queries.

Sorting and grouping

Last time, we mentioned the from, where and select keywords. Let's go over two more basic operators, before going into LINQ syntax details.

orderby

In order to sort query results, we use the orderby operator:

var query = from u in users
            where (u.Age > 15)
            orderby u.FirstName
            select u.Age;

As you already know, C# will translate this query into methods:

var query = users.Where(u => u.Age > 15).OrderBy(u => u.FirstName).Select(u => u.Age);

All LINQ clauses have their own methods, I just included it as a reminder, I won't attach the "method" version of the query in any of the examples later on.

The default sorting direction is from the smallest values to the largest ones. Here, we're sorting alphabetically based on the users' names. If we wanted to sort in the opposite direction, we'd simply use the descending keyword:

var query = from u in users
            where (u.Age > 15)
            orderby u.FirstName descending
            select u.Age;

In the original example, we could have used the ascending keyword, but not necessarily. If we were to use a method, we'd use OrderByDescen­ding().

We are even able to sort by multiple criteria, separated by commas. The first one is the most important:

var query = from u in users
            where (u.Age > 15)
            orderby u.FirstName, u.LastName
            select u.Age;

This query will be translated by C# to:

var query = users.Where(u => u.Age > 15).OrderBy(u => u.FirstName).ThenBy(u => u.LastName).Select(u => u.Age);

Group (grouping)

We often use grouping in our queries. We simply group the elements according to certain criteria. Here's an example of how we would put users into age, groups:

var query = from u in users
            group u by u.Age into ageGroup
            select new { Age = ageGroup.Key, Users = ageGroup };

What have we done? We've grouped users by their age into ageGroup, which is a collection containing users of the same age. Meaning that we now have groups such as group 15, group 16, 17, etc. Later on, we'll be able to select what the group will look like. We'll take the age from the group's keys which include the age since we're grouping based on this criteria. The second property for each group will be a user collection, where we'll store the current group of users for a given age.

Let's move on to printing:

foreach (var group in query)
{
        Console.WriteLine(group.Age);
        foreach (var user in group.Users)
                Console.WriteLine(user.FirstName);
}

We iterate over all of the groups, print the age, and then print out the users for each group.

In the next lesson, LINQ operators in C# .NET, we'll continue learning about LINQ syntax and run queries on multiple collections.


 

 

Article has been written for you by David Capka
Avatar
Do you like this article?
1 votes
The author is a programmer, who likes web technologies and being the lead/chief article writer at ICT.social. He shares his knowledge with the community and is always looking to improve. He believes that anyone can do what they set their mind to.
Unicorn College The author learned IT at the Unicorn College - a prestigious college providing education on IT and economics.
Thumbnail
All articles in this section
Collections and LINQ in C# .NET
Activities (7)

 

 

Comments

To maintain the quality of discussion, we only allow registered members to comment. Sign in. If you're new, Sign up, it's free.

No one has commented yet - be the first!