Linq allows querying data that are available in various different formats using a unified querying model.
We might query data in one of the following representations:
Relational data using SQL
In-Memory Data as object graphs
XML documents
…
Linq uses a declarative programming paradigm. You define what you want, not how to get there.
# Linq - Basics (2)
A Linq Query consists of 3 steps:
Define a data source
Create a query
Execute the query
# Linq - Data Source
Linq heavily build on the IEnumerable and IQueryable interfaces. Whenever a data source implements one of these interfaces, Linq can be used to query the data behind it.
IEnumerable - return element after element
IQueryable - more powerful: allows to query & return element after element
If a datasource doesn’t offer one of these interfaces, the data must be loaded into memory (e.g. into a List, Array, or similar that implements IEnumerable) to be able to query it.
# Linq - Data Source (2)
# Linq - Create a query
Linq offers 2 different ways of creating a query
Query Expressions
Method Syntax
# Query Expressions
Query expressions look similar to SQL statements. These expressions are built into the C# language and converted by the compiler to method calls.
# Query Expressions (2)
# Method syntax
The same query can be defined using regular C# method calls and lambda expressions.
# Linq - Execute the query
Depending on the underlying implementation of the data source, executing the query might mean completely different things.
E.g. when querying data stored in memory (e.g. List<Product>) it will use C# methods to create the result. When talking to a database using an IQueryable object, an SQL query will be generated instead and executed on the database (that’s called Linq to SQL btw).
When talking to RAM it’s called Linq to Object
# Linq - Executing the query
You can execute a query by enumerating the elements of the IEnumerable interface, for example using a foreach loop, or by calling ToList:
# Deferred execution / Lazy evaluation
When defining a Linq query, no operation on the underlying data source will be triggered. We only specify what will happen, once we actually execute the query.
Only by enumerating the query, calling ToList / ToArray, or similar we actually perform the operations specified in the query.
# Selection and Projection
When using a where operation, what we do is actually a selection. We choose which of the available items should be included in the result.
When using a select operation, what we do is actually a projection. We project one representation of data on another representation. For example instead of querying projects, we only query the name for each project.
# Linq - Select ( Projection)
# Linq - Select (Projection) (2)
# Linq - Select (Projection) (3)
For projection you can also use anonymous classes.
# Linq - Where (Selection)
We can use the where clause in Linq to restrict the data we want to return. This is called selection, or filtering.
# Linq - Where (Selection) (2)
# Linq - Where (Selection) (3)
# Linq - Where with delegate
# Linq - From
Use from to define the data source of your query.
# Linq - OrderBy
Use OrderBy to sort the elements of your query.
# Linq - OrderBy (2)
You can also define the order (ascending or descending). If not specified, ascending sorting will be used.
# Data Aggregation
You can use different forms of join operations with Linq.
# Linq - Inner Join
# Linq - Inner Join (2)
# Linq - Inner Join - Object Association
# Linq - Inner Join - Object Association (2)
# Linq - Inner Join - Composite Key
# Linq - Inner Join - Composite Key (2)
# Linq - Inner Join - Multiple Join
# Linq - Inner Join - Multiple Join (2)
# Linq - Partitioning
Partitioning operators are used to partition the result of a query.
# Linq - Partitioning (2)
Operators for Partitioning:
Skip
SkipWhile
Take
TakeWhile
# Linq - Partitioning (3)
Skip ignores the first n elements.
# Linq - Partitioning (4)
SkipWhile ignores elements at the beginning of the data source as long as they fulfil a certain condition.
[
# Linq - Partitioning (5)
Take limits the result to a certain amount of elements.
# Linq - Aggregation
Aggregation Operators can be used to find aggregates of multiple data entries.
# Linq - Aggregation (2)
Aggregation Operators:
Min, Max, Average
Count, Sum
Aggregate
# Linq - Aggregation (3)
# Linq - Aggregation (4)
# Linq - Aggregation (5)
# Linq - Grouping
Use tho group clause to group data.
# Linq - Grouping (2)
# Linq - Grouping (3)
# Linq - Grouping (4)
# Linq - Grouping (5)
Group elements by a single property.
# Linq - Grouping (6)
Group elements by a derived value.
# Linq - Grouping (7)
# Linq - Group and Filter
# Linq - Min, Max, Average
# Linq - Min, Max, Average (2)
# Linq - Set Operations
To further specify the data source of a query you can use set operations such as:
Distinct
Except
Intersect
Union
# Linq - Distinct
The Distinct method removes duplicates from the data source.
# Linq - Distinct (2)
# Linq - Except
# Linq - Except (2)
# Linq - Intersect
Intersect finds elements that appear in both data sources.
# Linq - Intersect (2)
# Linq - Union
Union combines two data sources to one, including all elements from both collections.
Union will also remove duplicates as long as the items can be compared using the overriden Equals method or an comparer object that implements the IEquatable<T> interface.
# Linq - Union (2)
# Linq - Quantifiers
Quantifiers classify a set of values. The return value of a quantifier is a boolean value.
Operators:
All
Any
Contains
# Linq - All
The All quantifier checks, whether each and everyone of the elements of a data source fulfils a condition.
# Linq - All (2)
# Linq - Any
The Any quantifier checks, whether at least one element fulfils a condition.
# Linq - Contains
The Contains quantifier checks whether a certain element exists in the data source.
# Linq - Subqueries
Subqueries are queries that are embedded into other queries.