LINQ - Overview

LINQ (Language-Integrated Query) is a technology in Microsoft's .NET Framework that allows developers to write queries to retrieve and manipulate data from a variety of data sources, including databases, collections, XML documents, and web services. LINQ provides a set of standard query operators that can be used to filter, sort, group, and aggregate data.

One of the key benefits of LINQ is that it allows developers to write queries using a syntax that is similar to SQL, which is a widely used language for querying databases. This makes it easier for developers who are familiar with SQL to learn LINQ and write queries more quickly.

LINQ also provides a number of other features, such as support for lambda expressions, which are a concise way to write anonymous functions, and type safety, which helps prevent runtime errors by ensuring that queries are written correctly at compile time.

Different Steps of a LINQ Query Operation

A LINQ query operation typically involves the following steps:

Data source:

The first step in a LINQ query operation is to define the data source that the query will operate on. The data source can be any object that implements the IEnumerable or IQueryable interface, including collections, arrays, databases, XML documents, and web services.

int[] numbers = { 1, 2, 3, 4, 5 };

Query creation:

The next step is to create the query itself. This is done using LINQ query syntax or method syntax, which allows you to specify what data you want to retrieve, how to filter and sort the data, and how to group and aggregate the data.

Using LINQ query syntax:
var query = from number in numbers where number % 2 == 0 select number;
Using method syntax:
var query = numbers.Where(number => number % 2 == 0);

Query execution:

Once the query has been created, it is executed using one of the execution methods provided by LINQ, such as ToList(), ToArray(), or FirstOrDefault(). These methods execute the query and return the results as a list, array, or single object, depending on the query.

var results = query.ToList();

Deferred execution:

One important aspect of LINQ is that queries are executed using deferred execution. This means that the query is not executed immediately when it is created, but rather when it is enumerated or when a specific execution method is called. This allows LINQ to optimize the query execution and improve performance.

var query = from number in numbers where number % 2 == 0 select number; // The query is not executed yet foreach (var number in query) { Console.WriteLine(number); } // The query is executed here

Results:

The final step is to consume the results of the query. This can be done by iterating over the results using a foreach loop, or by using LINQ to further manipulate or transform the data.

foreach (var number in results) { Console.WriteLine(number); }

Above code examples demonstrate the basic steps involved in a LINQ query operation, including defining a data source, creating a query using either query syntax or method syntax, executing the query, deferring execution, and consuming the results.

C# LinQ examples

Following is an example of a single C# program that demonstrates the different steps involved in a LINQ query operation:

using System; using System.Collections.Generic; using System.Linq; class MyProgram { static void Main(string[] args) { int[] numbers = { 1, 2, 3, 4, 5 }; var query = from number in numbers where number % 2 == 0 select number; var results = query.ToList(); foreach (var number in results) { Console.WriteLine(number); } Console.ReadLine(); } }
//Output: 2 4

Above program defines an array of integers, creates a LINQ query using query syntax to retrieve even numbers from the array, executes the query and stores the results in a list, and then iterates over the results to print them to the console. The program uses the Console.ReadLine() method to prevent the console window from closing before the user has a chance to view the results.

Query Syntax and Method Syntax | Examples

In LINQ, there are two main syntaxes that you can use to create queries: query syntax and method syntax.

Query Syntax

Query syntax uses a SQL-like syntax with keywords such as from, where, and select to create a query. Following is an example of a query that retrieves all the even numbers from an array of integers using query syntax:

int[] numbers = { 1, 2, 3, 4, 5 }; var query = from number in numbers where number % 2 == 0 select number;
//Output: 2 4

In this query, selecting all the numbers from the numbers array where number is even (i.e., where number % 2 == 0).

Method Syntax

Method syntax, on the other hand, uses a fluent interface with extension methods to create a query. Following is an example of the same query as above, but using method syntax:

int[] numbers = { 1, 2, 3, 4, 5 }; var query = numbers.Where(number => number % 2 == 0);
//Output: 2 4

In this query, using the Where extension method to filter the numbers array based on the same condition as above.

Both query syntax and method syntax are equivalent, and you can use either syntax to create LINQ queries. Some developers prefer one syntax over the other depending on personal preference or the specific requirements of the task at hand.

LINQ Simple select example

In LINQ, the Select method is used to project each element of a sequence into a new form, or to extract a subset of properties from an object. Following is an example of using Select to extract a subset of properties from a collection of Person objects:

using System; using System.Collections.Generic; using System.Linq; class Person { public string Name { get; set; } public int Age { get; set; } } class Program { static void Main(string[] args) { List<Person> people = new List<Person> { new Person { Name = "Bill", Age = 25 }, new Person { Name = "Doe", Age = 30 }, new Person { Name = "Annie", Age = 35 }, }; var names = people.Select(person => person.Name); foreach (var name in names) { Console.WriteLine(name); } } }
//Output: Bill Doe Annie

In the above example, ther is a collection of Person objects, and want to extract just the Name property of each Person. Use the Select method with a lambda expression that specifies the projection and want to apply to each Person. The lambda expression takes a Person object as input, and returns the value of the Name property. The result of the query is an IEnumerable containing the names of all the people in the people collection.

Note that the Select method is just one of many LINQ methods that you can use to transform and manipulate sequences of data. Other useful methods include Where (for filtering), OrderBy (for sorting), GroupBy (for grouping), and many more.

LINQ GroupBy and OrderBy example

Let's assume you have a List containing information about people, and you want to group them by their age and order each group by the number of people in it.

using System; using System.Collections.Generic; using System.Linq; class Person { public string Name { get; set; } public int Age { get; set; } } class MyProgram { static void Main(string[] args) { List<Person> people = new List<Person> { new Person { Name = "Bill", Age = 25 }, new Person { Name = "Joy", Age = 30 }, new Person { Name = "Cathy", Age = 35 }, new Person { Name = "Doe", Age = 30 }, new Person { Name = "Emily", Age = 25 } }; var groupedPeople = people .GroupBy(p => p.Age) .OrderByDescending(g => g.Count()); foreach (var group in groupedPeople) { Console.WriteLine($"Age: {group.Key}, Count: {group.Count()}"); foreach (var person in group) { Console.WriteLine($"\t{person.Name}"); } } } }
//Output: Age: 25, Count: 2 Bill Emily Age: 30, Count: 2 Joy Doe Age: 35, Count: 1 Cathy

In the above example, first create a List object with some sample data. Then use LINQ to group the people by their age using the GroupBy method, which returns an IEnumerable < IGrouping < int, Person > > where each IGrouping object represents a group of people with the same age.

LINQ OrderBy

Next, use the OrderByDescending method to sort the groups in descending order by the number of people in each group. This returns an IOrderedEnumerable < IGrouping < int, Person > > .

Finally, iterate through the groups using a foreach loop and print out the age of each group, the number of people in it, and the name of each person in the group. Note that you access the Key property of each group to get the age value that was used for grouping, and the Count method to get the number of people in the group.

LINQ SelectMany()

In LINQ, the SelectMany method is used to flatten a sequence of sequences (i.e., a nested sequence) into a single sequence. Following is an example of using SelectMany to flatten a collection of Person objects that have a collection of Hobbies into a single sequence of hobbies:

using System; using System.Collections.Generic; using System.Linq; class Person { public string Name { get; set; } public List<string> Hobbies { get; set; } } class Program { static void Main(string[] args) { List<Person> people = new List<Person> { new Person { Name = "Bill", Hobbies = new List<string> { "Reading", "Hiking" } }, new Person { Name = "Doe", Hobbies = new List<string> { "Cooking", "Gardening", "Fishing" } }, new Person { Name = "Cathy", Hobbies = new List<string> { "Playing music", "Painting" } }, }; var hobbies = people.SelectMany(person => person.Hobbies); foreach (var hobby in hobbies) { Console.WriteLine(hobby); } } }

In the above example, there is a collection of Person objects, where each Person has a collection of Hobbies. You want to extract all the Hobbies from all the Person objects into a single sequence of hobbies. Use the SelectMany method with a lambda expression that specifies how to extract the Hobbies from each Person. The lambda expression takes a Person object as input, and returns the Hobbies property of that Person. The SelectMany method then flattens the resulting sequence of sequences into a single sequence of hobbies.

var hobbies = people.SelectMany(person => person.Hobbies);

The result of the query is an IEnumerable containing all the hobbies of all the people in the people collection.

Note that SelectMany is a powerful method that can be used for many different scenarios. In addition to flattening nested sequences, it can be used to perform many-to-many joins, to concatenate sequences, and more.

LINQ count function

In LINQ, the Count method is used to count the number of elements in a sequence. Following is an example of using Count to count the number of elements in a collection of Person objects:

class Person { public string Name { get; set; } public int Age { get; set; } } List<Person> people = new List<Person> { new Person { Name = "Alice", Age = 25 }, new Person { Name = "Bob", Age = 30 }, new Person { Name = "Charlie", Age = 35 }, }; int count = people.Count();

In the above example, use the Count method with no arguments to count the number of elements in the people collection.

The result of the query is an int containing the number of people in the people collection.

Note that Count can also be used with a lambda expression that specifies a condition for which elements to count. For example, people.Count(person = > person.Age > 30) would count the number of people in the people collection whose age is greater than 30.

Lambda Expressions With LINQ


C# linq tutorial step by step

Lambda expressions are a concise way to represent a delegate or an expression tree. In LINQ, lambda expressions are often used to define the conditions and projections used in querying data. Folowing is an example of using lambda expressions with LINQ:

Joining data with Join():

using System; using System.Collections.Generic; using System.Linq; class Person { public string Name { get; set; } public int Age { get; set; } } class Pet { public string Name { get; set; } public int Age { get; set; } public string OwnerName { get; set; } } class Program { static void Main(string[] args) { List<Person> people = new List<Person> { new Person { Name = "Bill", Age = 25 }, new Person { Name = "Yang", Age = 30 }, new Person { Name = "Cathy", Age = 35 }, }; List<Pet> pets = new List<Pet> { new Pet { Name = "Linda", Age = 3, OwnerName = "Bill" }, new Pet { Name = "Miko", Age = 5, OwnerName = "Yang" }, new Pet { Name = "Sony", Age = 2, OwnerName = "Cathy" }, }; var petOwners = people.Join(pets, person => person.Name, pet => pet.OwnerName, (person, pet) => new { Person = person, Pet = pet }); foreach (var petOwner in petOwners) { Console.WriteLine($"Person: {petOwner.Person.Name}, Pet: {petOwner.Pet.Name}"); } } }
//Output: Person: Bill, Pet: Linda Person: Yang, Pet: Miko Person: Cathy, Pet: Sony

In the above example, there are two collections (people and pets) that want to join based on the Name and OwnerName properties, respectively. Use the Join method with lambda expressions that define the key selectors (person => person.Name and pet => pet.OwnerName) and the result selector ((person, pet) => new { Person = person, Pet = pet }). The result selector takes a Person and a Pet as input, and returns an anonymous object that combines the two into a single object with properties Person and Pet.

By following these steps, developers can use LINQ to efficiently retrieve, manipulate, and transform data from a variety of sources.