Featured image of post LINQ in a Nutshell

LINQ in a Nutshell

LINQ in a Nutshell

LINQ Logo

LINQ in a Nutshell

Ever found yourself tangled in loops and conditionals just to fetch some data?

Wish you could just ask for what you want, like ordering a coffee?

Well, say hello to LINQ!

A Quick Trip Down Memory Lane: The History of LINQ

Once upon a time in the mid-2000s, developers were juggling different query languages for databases, XML, and in-memory collections.

It was like trying to speak multiple languages at once—confusing and error-prone. Enter LINQ (Language Integrated Query), introduced by Microsoft in 2007 as part of .NET Framework 3.5.

LINQ unified data querying across various data sources, making it as smooth as butter on a hot pancake.

Now, developers could write queries directly in C# or VB.NET, bringing type safety and IntelliSense support to their fingertips. Source: Wikipedia

The Many Flavors of LINQ

LINQ is like that Swiss Army knife in your coding toolkit. Let’s slice through its main uses:

1. LINQ to Objects

Got a collection? LINQ’s got you. Whether it’s arrays, lists, or dictionaries, you can filter, project, and aggregate data with style.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System;
using System.Linq;
using System.Collections.Generic;

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public class Program
{
    public static void Main()
    {
        List<Person> people = new List<Person>
        {
            new Person { Name = "Alice", Age = 25 },
            new Person { Name = "Bob", Age = 18 },
            new Person { Name = "Charlie", Age = 30 }
        };

        // Fetching adults
        var adults = people.Where(p => p.Age >= 18).ToList();

        foreach (var adult in adults)
        {
            Console.WriteLine(adult.Name);
        }
    }
}

Explanation: Where() filters the collection based on the provided condition, and ToList() executes the query and converts the result into a list.

Common LINQ Method Syntax Methods:
  • Where() – Filters elements based on a predicate.
  • Select() – Projects elements to a new form.
  • OrderBy()/OrderByDescending() – Orders elements in ascending or descending order.
  • GroupBy() – Groups elements based on a key.
  • Take() – Limits the number of items returned.
  • Skip() – Skips a specified number of items.
  • FirstOrDefault()/SingleOrDefault() – Returns the first or single item that matches the criteria.****

2. LINQ to SQL

Talking to SQL Server?

LINQ acts as your translator, letting you interact with your database using your favorite C# syntax. It’s like having a bilingual buddy who makes sure nothing gets lost in translation.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.Linq;

public class Program
{
    public static void Main()
    {
        using (var context = new DataContext()) // Assuming a DataContext class generated by LINQ to SQL
        {
            var query = from p in context.People
                        where p.Age >= 18
                        select p;

            foreach (var person in query)
            {
                Console.WriteLine(person.Name);
            }
        }
    }
}
  • Explanation: The query syntax uses keywords like from, where, and select, which closely resemble SQL statements. It allows for more readable and compact code, especially in complex queries.
Common LINQ Query Syntax Clauses:
  • from – Specifies the data source.
  • where – Filters data based on a condition.
  • select – Projects data into a new form.
  • orderby – Sorts data based on specified criteria.
  • join – Joins multiple data sources.
  • group – Groups elements based on a specified key.

3. LINQ to Entities (Entity Framework)

Think of this as LINQ to SQL’s beefed-up cousin.

With Entity Framework, you can work with multiple databases, and LINQ makes querying them a breeze.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
using System.Linq;

public class Program
{
    public static void Main()
    {
        using (var context = new ApplicationDbContext()) // Assuming an ApplicationDbContext class for EF
        {
            var adults = context.People
                                .Where(p => p.Age >= 18)
                                .OrderBy(p => p.Name)
                                .ToList();

            foreach (var person in adults)
            {
                Console.WriteLine(person.Name);
            }
        }
    }
}

4. LINQ to XML

Parsing XML can feel like deciphering ancient scripts. LINQ to XML makes it as easy as reading a bedtime story.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
using System.Linq;
using System.Xml.Linq;

public class Program
{
    public static void Main()
    {
        string xml = "<people><person><name>Alice</name><age>25</age></person><person><name>Bob</name><age>18</age></person></people>";
        XDocument doc = XDocument.Parse(xml);

        var adults = from p in doc.Descendants("person")
                     where (int)p.Element("age") >= 18
                     select new
                     {
                         Name = p.Element("name").Value,
                         Age = (int)p.Element("age")
                     };

        foreach (var person in adults)
        {
            Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
        }
    }
}

5. LINQ to DataSet

Got a DataSet from the ADO.NET days?

LINQ can still work its magic, letting you query those tables like a pro.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System;
using System.Data;
using System.Linq;

public class Program
{
    public static void Main()
    {
        // Create a DataTable with sample data
        DataTable table = new DataTable();
        table.Columns.Add("Name");
        table.Columns.Add("Age", typeof(int));

        table.Rows.Add("Alice", 25);
        table.Rows.Add("Bob", 18);
        table.Rows.Add("Charlie", 30);

        // LINQ query to filter data
        var adults = from row in table.AsEnumerable()
                     where row.Field<int>("Age") >= 18
                     select new
                     {
                         Name = row.Field<string>("Name"),
                         Age = row.Field<int>("Age")
                     };

        foreach (var person in adults)
        {
            Console.WriteLine($"{person.Name} is {person.Age} years old.");
        }
    }
}

6. Parallel LINQ (PLINQ)

Need speed? PLINQ runs your queries in parallel, making heavy data lifting feel like a feather.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
using System;
using System.Linq;

public class Program
{
    public static void Main()
    {
        int[] numbers = Enumerable.Range(1, 10000000).ToArray();

        // Use PLINQ to process the numbers in parallel
        var evenNumbers = numbers.AsParallel().Where(n => n % 2 == 0).ToArray();

        Console.WriteLine($"There are {evenNumbers.Length} even numbers.");
    }
}

7. Asynchronous LINQ Queries

Why wait? Combine LINQ with async programming to keep your apps responsive and your users happy.

Example:

Below is an asynchronous LINQ query using Entity Framework Core, which supports asynchronous operations via ToListAsync(), FirstOrDefaultAsync(), etc.

Example: Asynchronous LINQ Query in Entity Framework Core

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

public class ApplicationDbContext : DbContext
{
    public DbSet<Person> People { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlite("Data Source=people.db"); // Example using SQLite
}

public class Program
{
    public static async Task Main()
    {
        using var context = new ApplicationDbContext();

        // Ensure database is created and seeded
        await context.Database.EnsureCreatedAsync();
        if (!await context.People.AnyAsync())
        {
            context.People.AddRange(new Person { Name = "Alice", Age = 25 }, new Person { Name = "Bob", Age = 18 });
            await context.SaveChangesAsync();
        }

        // Asynchronous LINQ query
        var adults = await context.People
                                  .Where(p => p.Age >= 18)
                                  .OrderBy(p => p.Name)
                                  .ToListAsync();

        foreach (var person in adults)
        {
            Console.WriteLine($"{person.Name} ({person.Age} years old)");
        }
    }
}
  • Explanation:
    • Asynchronous Query Execution: ToListAsync() ensures the database query runs asynchronously.
    • Entity Framework Core Integration: Works with real databases.
    • Ensuring Database Exists: EnsureCreatedAsync() prevents errors when running the example.

The example can handle database queries without blocking the main thread! 🚀

8. Raw SQL Queries

Entity Framework allows you to write raw SQL queries, which can be useful when you need to use complex SQL features that aren’t easily expressible in LINQ or for performance optimizations.

Example: Fetching all active users using raw SQL:
1
2
3
var activeUsers = context.Users
                         .FromSqlRaw("SELECT * FROM Users WHERE IsActive = 1")
                         .ToList();
  • Explanation: The FromSqlRaw() method allows you to run raw SQL queries against the database. You can use parameterized queries to prevent SQL injection.
Common Raw SQL Query Methods:
  • FromSqlRaw() – Executes a raw SQL query and maps the result to entities.
  • ExecuteSqlRaw() – Executes a raw SQL command without expecting any results, typically used for updates, inserts, or deletes.
Example of Parameterized Raw SQL:
1
2
3
var activeUsers = context.Users
                         .FromSqlRaw("SELECT * FROM Users WHERE IsActive = {0}", true)
                         .ToList();

In this case, {0} is replaced by the value true, which ensures safe query execution.


9. Compiled Queries

Entity Framework allows you to compile queries that can improve performance by reducing query parsing and translation overhead. This is especially helpful for frequently executed queries.

Example: Compiling a query:
1
2
var query = EF.CompileQuery((DbContext context) =>
    context.Users.Where(u => u.IsActive).ToList());
  • Explanation: CompileQuery() is used to compile a LINQ query and cache it for future executions, improving performance in cases where the same query is executed repeatedly.

10. Entity Framework Core: Asynchronous Queries

With Entity Framework Core, you can perform queries asynchronously to avoid blocking the thread, especially for I/O-bound operations like database queries.

Example: Asynchronous LINQ Method Syntax:
1
2
3
4

var activeUsers = await context.Users
                               .Where(u => u.IsActive)
                               .ToListAsync();
  • Explanation: ToListAsync() is an asynchronous version of ToList(). It returns a Task, allowing the application to continue executing while waiting for the database query to complete.

11. GroupBy with Aggregates

You can also perform aggregations using LINQ in Entity Framework. This is particularly useful for queries that need to group data and compute values like sums, averages, or counts.

Example: Grouping and Counting:
1
2
3
4
5
6
7
8

var userCountsByCountry = from user in context.Users
                          group user by user.Country into userGroup
                          select new
                          {
                              Country = userGroup.Key,
                              UserCount = userGroup.Count()
                          };
  • Explanation: group by is used to group users by their country, and Count() is used to get the number of users in each group.