Skip to main content

.NET LINQ Query Syntax

Introduction

LINQ (Language Integrated Query) is one of the most powerful features in .NET, allowing developers to query data from various sources using a consistent syntax. LINQ provides two main syntaxes for writing queries: the method syntax (also known as fluent syntax) and the query syntax.

In this tutorial, we'll focus on LINQ's query syntax, which resembles SQL and provides a more readable, declarative approach to querying collections. Query syntax is particularly helpful for beginners and those familiar with SQL as it presents queries in a more human-readable format.

What is LINQ Query Syntax?

LINQ query syntax is a SQL-like syntax integrated directly into C# that allows you to write queries against collections. It starts with a from clause and typically ends with a select or group clause, with various optional clauses in between.

Here's a basic structure:

csharp
var query = from element in collection
where condition
select element;

This approach makes complex data manipulations more readable and maintainable compared to traditional loops and conditions.

Basic Query Syntax Elements

Let's break down the essential components of LINQ query syntax:

1. from Clause

The from clause specifies the data source and a range variable:

csharp
from student in students
  • student: The range variable (represents each item during iteration)
  • students: The data source (collection being queried)

2. where Clause

The where clause filters elements based on a condition:

csharp
where student.Age > 18

3. select Clause

The select clause specifies what data to retrieve:

csharp
select student
// or
select new { student.Name, student.Age }

Your First LINQ Query

Let's see a complete example:

csharp
using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
static void Main()
{
// Data source
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// LINQ query to find even numbers
var evenNumbers = from num in numbers
where num % 2 == 0
select num;

// Display results
Console.WriteLine("Even numbers:");
foreach (var num in evenNumbers)
{
Console.Write(num + " ");
}
// Output: Even numbers: 2 4 6 8 10
}
}

In this example:

  1. We define a list of integers
  2. We create a LINQ query that selects numbers where num % 2 == 0 (even numbers)
  3. We execute the query by iterating through the results

Ordering Results with orderby

The orderby clause lets you sort results:

csharp
List<Student> students = new List<Student>
{
new Student { Name = "Alice", Age = 19 },
new Student { Name = "Bob", Age = 21 },
new Student { Name = "Charlie", Age = 18 }
};

var sortedStudents = from student in students
orderby student.Age ascending
select student;

// Output:
// Charlie, 18
// Alice, 19
// Bob, 21

// For descending order:
var descendingOrder = from student in students
orderby student.Age descending
select student;

Grouping Results with group by

The group by clause allows you to group results by a key:

csharp
List<Student> students = new List<Student>
{
new Student { Name = "Alice", Grade = "A" },
new Student { Name = "Bob", Grade = "B" },
new Student { Name = "Charlie", Grade = "A" },
new Student { Name = "Dave", Grade = "B" }
};

var groupedStudents = from student in students
group student by student.Grade into gradeGroup
select new { Grade = gradeGroup.Key, Students = gradeGroup };

foreach (var group in groupedStudents)
{
Console.WriteLine($"Grade {group.Grade}:");
foreach (var student in group.Students)
{
Console.WriteLine($"- {student.Name}");
}
}

// Output:
// Grade A:
// - Alice
// - Charlie
// Grade B:
// - Bob
// - Dave

Joining Collections with join

The join clause allows you to combine data from multiple collections:

csharp
List<Student> students = new List<Student>
{
new Student { Id = 1, Name = "Alice" },
new Student { Id = 2, Name = "Bob" }
};

List<Course> courses = new List<Course>
{
new Course { StudentId = 1, CourseName = "Math" },
new Course { StudentId = 1, CourseName = "Physics" },
new Course { StudentId = 2, CourseName = "Chemistry" }
};

var studentCourses = from student in students
join course in courses
on student.Id equals course.StudentId
select new { StudentName = student.Name, Course = course.CourseName };

foreach (var item in studentCourses)
{
Console.WriteLine($"{item.StudentName} is enrolled in {item.Course}");
}

// Output:
// Alice is enrolled in Math
// Alice is enrolled in Physics
// Bob is enrolled in Chemistry

Let Clause for Temporary Variables

The let clause creates a temporary variable within a query:

csharp
List<string> names = new List<string> { "Alice Smith", "Bob Johnson", "Charlie Brown" };

var nameInfo = from fullName in names
let nameParts = fullName.Split(' ')
let firstName = nameParts[0]
let lastName = nameParts[1]
select new { FirstName = firstName, LastName = lastName, FullName = fullName };

foreach (var person in nameInfo)
{
Console.WriteLine($"First name: {person.FirstName}, Last name: {person.LastName}");
}

// Output:
// First name: Alice, Last name: Smith
// First name: Bob, Last name: Johnson
// First name: Charlie, Last name: Brown

Practical Example: Employee Management System

Let's create a more complex real-world example for an employee management system:

csharp
using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
static void Main()
{
// Sample data
List<Department> departments = new List<Department>
{
new Department { Id = 1, Name = "Engineering" },
new Department { Id = 2, Name = "Marketing" },
new Department { Id = 3, Name = "HR" }
};

List<Employee> employees = new List<Employee>
{
new Employee { Id = 101, Name = "Alice", DeptId = 1, Salary = 75000, YearsOfService = 3 },
new Employee { Id = 102, Name = "Bob", DeptId = 2, Salary = 65000, YearsOfService = 2 },
new Employee { Id = 103, Name = "Charlie", DeptId = 1, Salary = 85000, YearsOfService = 5 },
new Employee { Id = 104, Name = "Diana", DeptId = 3, Salary = 70000, YearsOfService = 4 },
new Employee { Id = 105, Name = "Eva", DeptId = 2, Salary = 90000, YearsOfService = 6 },
new Employee { Id = 106, Name = "Frank", DeptId = 1, Salary = 72000, YearsOfService = 2 }
};

// Query 1: Find employees who earn more than 70,000 and have been with the company for at least 3 years
var seniorHighEarners = from emp in employees
where emp.Salary > 70000 && emp.YearsOfService >= 3
orderby emp.Salary descending
select new { emp.Name, emp.Salary, emp.YearsOfService };

Console.WriteLine("Senior high-earning employees:");
foreach (var emp in seniorHighEarners)
{
Console.WriteLine($"{emp.Name} - ${emp.Salary}, {emp.YearsOfService} years");
}

// Query 2: Department-wise employee count and average salary
var deptStats = from emp in employees
group emp by emp.DeptId into deptGroup
join dept in departments
on deptGroup.Key equals dept.Id
select new {
Department = dept.Name,
EmployeeCount = deptGroup.Count(),
AverageSalary = deptGroup.Average(e => e.Salary)
};

Console.WriteLine("\nDepartment statistics:");
foreach (var stat in deptStats)
{
Console.WriteLine($"{stat.Department}: {stat.EmployeeCount} employees, Avg salary: ${stat.AverageSalary:F2}");
}

// Query 3: Find highest paid employee in each department
var topEarners = from dept in departments
join emp in employees
on dept.Id equals emp.DeptId
group emp by dept.Name into deptGroup
let maxSalary = deptGroup.Max(e => e.Salary)
let topEmployee = deptGroup.First(e => e.Salary == maxSalary)
select new {
Department = deptGroup.Key,
EmployeeName = topEmployee.Name,
Salary = maxSalary
};

Console.WriteLine("\nHighest paid employee in each department:");
foreach (var topEarner in topEarners)
{
Console.WriteLine($"{topEarner.Department}: {topEarner.EmployeeName} (${topEarner.Salary})");
}
}
}

class Department
{
public int Id { get; set; }
public string Name { get; set; }
}

class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int DeptId { get; set; }
public double Salary { get; set; }
public int YearsOfService { get; set; }
}

Output:

Senior high-earning employees:
Eva - $90000, 6 years
Charlie - $85000, 5 years
Diana - $70000, 4 years

Department statistics:
Engineering: 3 employees, Avg salary: $77333.33
Marketing: 2 employees, Avg salary: $77500.00
HR: 1 employees, Avg salary: $70000.00

Highest paid employee in each department:
Engineering: Charlie ($85000)
Marketing: Eva ($90000)
HR: Diana ($70000)

When to Use Query Syntax vs. Method Syntax

While both syntaxes can achieve the same results, each has its advantages:

Use Query Syntax when:

  • You're writing complex queries with multiple operations
  • You're more familiar with SQL
  • Your query involves joins, grouping, or filtering with multiple conditions

Use Method Syntax when:

  • You're performing simple operations (single filter, projection)
  • You need to use LINQ operators that don't have query syntax equivalents (like Skip, Take, Distinct)
  • You prefer chaining methods for readability

Summary

LINQ query syntax provides a powerful, readable way to query collections in .NET. In this tutorial, we've covered:

  • The basic structure of LINQ query syntax
  • How to filter, project, and sort data
  • Grouping and joining collections
  • Using temporary variables with the let clause
  • A practical example with complex queries

Learning LINQ query syntax is essential for .NET developers as it makes data manipulation more concise and readable. While method syntax is equally powerful, query syntax often provides better readability for complex queries, especially for those familiar with SQL.

Additional Resources and Exercises

Resources

Exercises

  1. Basic Exercise: Create a list of products with properties Name, Price, and Category. Write a LINQ query to find all products in a specific category with a price less than a given amount.

  2. Intermediate Exercise: Create two lists: Authors and Books, where Books contains an AuthorId. Write a LINQ query to find all authors who have written more than 3 books and order them by the number of books they've written.

  3. Advanced Exercise: Create three related collections: Students, Courses, and Enrollments (joining Students and Courses). Write a LINQ query to find the most popular course (with the most enrollments) and list all students enrolled in it.

By practicing these exercises, you'll develop a strong grasp of LINQ query syntax and be able to apply it effectively in your .NET projects.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)