.NET Framework .NET C# VB.NET LINQ ASP.NET Web API REST SignalR Windows Forms WPF WCF RabbitMQ PHP SQL Server MySQL PostgreSQL MariaDB SQLite MongoDB ADO.NET ORM Entity Framework Dapper XML JSON HTML5 CSS3 Bootstrap JavaScript jQuery Angular React TypeScript NPM Blazor UI/UX Responsive Web Design Redis Elasticsearch GraphQL Grafana Agile Scrum Kanban Windows Server IIS PowerShell Active Directory TFS Azure Automation Software Reverse Engineering Performance Optimization Git Jira/Confluence CI/CD TeamCity SOLID KISS DRY YAGNI
Always will be ready notify the world about expectations as easy as possible: job change page

Advanced LINQ you must know in C# .NET

Created: May 12, 2023
Author: Alex Maher
Source: source
Views: 326

Language Integrated Query (LINQ) is a powerful feature in C# .NET that allows developers to query various data sources using a consistent syntax. In this article, we’ll explore some advanced LINQ techniques to help you level up your skills and write more efficient code.

Advanced LINQ

LINQ Extension Methods

LINQ comes with many built-in extension methods, but you can also create your own custom methods to extend LINQ’s capabilities.

Custom Extension Methods

By creating your own extension methods, you can encapsulate complex logic and reuse it throughout your application. To create a custom extension method, you need to create a static method in a static class and use the this keyword before the type parameter.

Example: FilterByLength

public static class StringExtensions
    public static IEnumerable<string> FilterByLength(this IEnumerable<string> source, int minLength)
        return source.Where(s => s.Length >= minLength);

Aggregate Functions

LINQ provides several aggregate functions to perform operations on collections, such as Sum, Min, Max, and Average.

Count and Any

The Count function returns the number of elements in a collection that satisfy a given condition, while the Any function checks if any elements in the collection satisfy the condition.

Code Examples

List<Product> products = GetProducts();

int highPriceCount = products.Count(p => p.Price > 100);
bool hasHighPrice = products.Any(p => p.Price > 100);

Sum, Min, Max, and Average

These functions can be used on collections of numeric data types or with a selector function to calculate the aggregate value of a specific property.

Code Examples

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

int sum = numbers.Sum();
int min = numbers.Min();
int max = numbers.Max();
double average = numbers.Average();

List<Product> products = GetProducts();
decimal totalValue = products.Sum(p => p.Price);

Grouping and Aggregating Data

LINQ provides methods to group and aggregate data based on specific properties or conditions.

GroupBy Method

The GroupBy method allows you to group elements in a collection based on a key selector function. The result is a collection of groups, each containing elements with the same key value.

Example: GroupBy Category

List<Product> products = GetProducts();

var groupedProducts = products.GroupBy(p => p.Category);

foreach (var group in groupedProducts)
    Console.WriteLine($"Category: {group.Key}");
    foreach (var product in group)
        Console.WriteLine($"  Product: {product.Name}");

GroupJoin Method

The GroupJoin method allows you to perform a grouped join between two collections based on a key selector function for each collection.

Example: GroupJoin on Customers

List<Customer> customers = GetCustomers();
List<Order> orders = GetOrders();

var customerOrders = customers.GroupJoin(orders,
    customer => customer.Id,
    order => order.CustomerId,
    (customer, orderGroup) => new
        Customer = customer,
        Orders = orderGroup

foreach (var item in customerOrders)
    Console.WriteLine($"Customer: {item.Customer.Name}");
    foreach (var order in item.Orders)
        Console.WriteLine($"  Order: {order.Id}");

Dynamic LINQ Queries

Using the Dynamic LINQ library, you can create queries at runtime by providing query strings or expressions.

Dynamic Sorting and Grouping

Using Dynamic LINQ, you can also perform dynamic sorting and grouping of data.

Example: Dynamic OrderBy

using System.Linq.Dynamic.Core;

List<Product> products = GetProducts();
string sortBy = "Price descending";

var sortedProducts = products.AsQueryable().OrderBy(sortBy);

Using Dynamic LINQ Library

To use the Dynamic LINQ library, you need to install the System.Linq.Dynamic.Core NuGet package.

Install-Package System.Linq.Dynamic.Core

Dynamic Expressions and Predicates

With the Dynamic LINQ library, you can create dynamic expressions and predicates in your LINQ queries.

Example: Dynamic Where

using System.Linq.Dynamic.Core;

List<Product> products = GetProducts();
string filter = "Price > 100";

var filteredProducts = products.AsQueryable().Where(filter);

Deferred vs. Immediate Execution

LINQ supports two types of query execution: deferred and immediate.

Deferred Execution Benefits

Deferred execution means that the query is not executed until the results are enumerated. This can lead to performance improvements, as the query is only executed when necessary.

Example: Deferred Execution

var productsQuery = products.Where(p => p.Price > 100);

// The query is not executed yet
Console.WriteLine("Query created.");

// The query is executed when the results are enumerated
foreach (var product in productsQuery)

Immediate Execution Benefits

Immediate execution means that the query is executed as soon as it’s defined. This can be useful when the results need to be cached or if the data source might change before the results are enumerated.

Example: Immediate Execution

List<Product> expensiveProducts = products.Where(p => p.Price > 100).ToList();

// The query is executed immediately
Console.WriteLine("Expensive products retrieved.");

Advanced Query Operators

LINQ provides several advanced query operators to perform complex operations on collections.

Distinct and Reverse

The Distinct method returns a collection of unique elements based on a specified key selector, while the Reverse method reverses the order of elements in a collection.

Example: Unique and Reversed

List<int> numbers = new List<int> { 1, 2, 3, 3, 4, 5 };

var uniqueNumbers = numbers.Distinct(); // { 1, 2, 3, 4, 5 }
var reversedNumbers = numbers.Reverse(); // { 5, 4, 3, 3, 2, 1 }

Skip and Take

The Skip and Take methods can be used to implement paging in your LINQ queries.

Example: Paging

int pageSize = 10;
int pageNumber = 2;

var pagedProducts = products.Skip((pageNumber - 1) * pageSize).Take(pageSize);

Concat and Union

The Concat and Union methods can be used to merge two collections.

Example: Merging Data

List<int> numbers1 = new List<int> { 1, 2, 3 };
List<int> numbers2 = new List<int> { 3,4, 5 };

var concatenated = numbers1.Concat(numbers2); // { 1, 2, 3, 3, 4, 5 }
var union = numbers1.Union(numbers2); // { 1, 2, 3, 4, 5 }

Performance Optimization Techniques

There are several techniques to optimize the performance of your LINQ queries.

Indexing and Partitioning

You can optimize your LINQ queries by using indexing and partitioning techniques, which can significantly improve the performance of your queries, especially when working with large data sets.

Example: Indexing

List<Product> products = GetProducts();

var indexedProducts = products
    .Select((product, index) => new { Product = product, Index = index })
    .Where(item => item.Index % 2 == 0)
    .Select(item => item.Product);

Caching Results with AsEnumerable

Using AsEnumerable, you can cache the results of a query to avoid re-executing it multiple times.

Example: Caching Results

var productsQuery = products.Where(p => p.Price > 100);

IEnumerable<Product> cachedResults = productsQuery.AsEnumerable();

// Using cachedResults will not re-execute the query

Using Compiled Queries

Compiled queries can improve performance by caching the query plan for a specific query. This can be especially useful for frequently executed queries.

Example: Compiled Query

using System.Data.Linq;
using System.Data.Linq.Mapping;

[Table(Name = "Products")]
public class Product
    // ...

public class MyDataContext : DataContext
    public Table<Product> Products;

    public MyDataContext(string connection) : base(connection) { }

static Func<MyDataContext, IQueryable<Product>> compiledQuery =
    CompiledQuery.Compile((MyDataContext context) =>
        from p in context.Products
        where p.Price > 100
        select p);

using (MyDataContext context = new MyDataContext(connectionString))
    var results = compiledQuery(context);

Advanced LINQ to SQL

LINQ to SQL allows you to query relational databases using LINQ.

Multi-Threading and Parallelism

LINQ to SQL supports multi-threading and parallelism to improve query performance. Using the AsParallel method, you can execute a LINQ query across multiple threads to take advantage of multi-core processors.

Example: Parallel Execution

using System.Linq.Parallel;

List<Product> products = GetProducts();

var expensiveProducts = products.AsParallel().Where(p => p.Price > 100);

Querying Complex Data Types

You can use LINQ to SQL to query complex data types, such as XML data.

Example: Querying XML Data

XDocument xmlDoc = XDocument.Load("products.xml");

var products = xmlDoc.Descendants("Product")
    .Select(x => new
        Name = x.Element("Name").Value,
        Price = decimal.Parse(x.Element("Price").Value)

var expensiveProducts = products.Where(p => p.Price > 100);

Stored Procedures and Functions

LINQ to SQL allows you to call stored procedures and functions from your .NET code. This can improve performance and enable you to reuse existing database logic.

Example: Calling a Stored Procedure

using System.Data.Linq;

public class MyDataContext : DataContext
    public Table<Product> Products;

    [Function(Name = "GetExpensiveProducts")]
    public ISingleResult<Product> GetExpensiveProducts([Parameter] decimal minPrice)
        return ExecuteMethodCall(this, (MethodInfo)MethodInfo.GetCurrentMethod(), minPrice).ReturnValue as ISingleResult<Product>;

    public MyDataContext(string connection) : base(connection) { }

using (MyDataContext context = new MyDataContext(connectionString))
    var expensiveProducts = context.GetExpensiveProducts(100);

Transaction Management

LINQ to SQL supports transaction management to ensure data consistency.

Example: Transaction Control

using (MyDataContext context = new MyDataContext(connectionString))
    using (TransactionScope ts = new TransactionScope())
            // Perform database operations

        catch (Exception ex)
            // Handle exception

• • •


  1. What is the difference between the Concat and Union methods in LINQ? The Concat method combines two collections, keeping duplicate elements, whereas the Union method combines the collections, removing duplicates based on the default equality comparer.
  2. How can I use LINQ to query XML data? You can use LINQ to XML, a subset of LINQ, to query XML data by loading the XML data into an XDocument object and then using LINQ to query the elements in the document.
  3. How can I improve the performance of my LINQ to SQL queries? You can improve the performance of LINQ to SQL queries by caching query results using AsEnumerable, using compiled queries, managing transactions, and taking advantage of multi-threading and parallelism.
  4. What is the difference between deferred and immediate execution in LINQ? Deferred execution means that a query is not executed until the results are enumerated, while immediate execution means that the query is executed as soon as it’s defined.
  5. Can I call stored procedures and functions using LINQ to SQL? Yes, LINQ to SQL allows you to call stored procedures and functions from your .NET code, enabling you to reuse existing database logic and improve performance.

Thank you for reading! I hope this article helped you understand LINQ better and have learned something new :)

Jun 5, 2023
Author: Juan Alberto España Garcia
In this section, we’ll explore the world of unit testing in C# and .NET, learn what unit testing is, why it’s important, and the landscape of testing frameworks and tools available to developers.What is Unit Testing?Unit testing is the process...
Sep 11, 2023
Author: Artem A. Semenov
When crafting elegant and scalable software in C#, a keen understanding of Dependency Injection (DI) is more than a luxury — it’s a necessity. It’s a design pattern that underpins many modern .NET applications, providing a solid foundation for managing...
Jan 1, 2023
Author: Daniel Kreider
Here’s the simple step-by-step guide that will teach you how to build and code a generic repository.There are oodles of design patterns.Some of these design patterns are floating about on antique blogs full of mad logic. They’re ridiculous enough to...
Jun 2, 2023
Cyclomatic complexity is a code metric (integer value 1 or more) used to measure how complex a function/method is.It does not take into account lines of code but instead considers complexity to be the distinct paths through a function.Microsoft defines...
Send message
Your name

© 1999–2023 WebDynamics
1980–... Sergey Drozdov
Area of interests: .NET | .NET Core | C# | ASP.NET | Windows Forms | WPF | Windows Phone | HTML5 | CSS3 | jQuery | AJAX | MS SQL Server | Transact-SQL | ADO.NET | Entity Framework | IIS | OOP | OOA | OOD | WCF | WPF | MSMQ | MVC | MVP | MVVM | Design Patterns | Enterprise Architecture | Scrum | Kanban
GitHub profile