5 - LINQ
Language-Integrated Query (LINQ) is the name for a set of technologies based on the integration of query capabilities directly into the C# language1. Traditionally, queries against data are expressed as simple strings without type checking at compile time or IntelliSense support. Furthermore, you have to learn a different query language for each type of data source: SQL databases, XML documents, various Web services, and so on. With LINQ, a query is a first-class language construct, just like classes, methods, and events.
When you write queries, the most visible "language-integrated" part of LINQ is the query expression. You write query expressions in a declarative query syntax. By using query syntax, you perform filtering, ordering, and grouping operations on data sources with a minimum of code. You use the same query expression patterns to query and transform data from any type of data source.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
- Query expressions examine and transform data from any LINQ-enabled data source. For example, a single query can retrieve data from a SQL database and produce an XML stream as output.
- Query expressions use many familiar C# language constructs, which make them easy to read.
- The variables in a query expression are all strongly typed.
- A query isn't executed until you iterate over the query variable, for example in a foreach statement.
- At compile time, the compiler converts query expressions to standard query operator method calls according to the rules defined in the C# specification. You can express any query that uses query syntax by using method syntax. In some cases, query syntax is more readable and concise. In others, method syntax is more readable. There's no semantic or performance difference between the two different forms.
- Some query operations, such as Count or Max, have no equivalent query expression clause and must be expressed as a method call. You can combine method syntax with query syntax in various ways.
- Query expressions can be compiled to expression trees or to delegates, depending on the type that the query is applied to. The compiler compiles
IEnumerable<T>queries to delegates. The compiler compilesIQueryableandIQueryable<T>queries to expression trees.
Immediate execution means that the data source is read and the operation is performed once.
All the standard query operators that return a scalar result execute immediately.
Examples of such queries are Count, Max, Average, and First.
You can force any query to execute immediately using the ToList or ToArray methods.2
1 2 3 4 5 6 7 | |
To force immediate execution of any query and cache its results, you can call the ToList or ToArray methods.
1 2 3 4 5 6 7 | |
Deferred execution means that the operation isn't performed at the point in the code where the query is declared. The operation is performed only when the query variable is enumerated, for example by using a foreach statement. The results of executing the query depend on the contents of the data source when the query is executed rather than when the query is defined. If the query variable is enumerated multiple times, the results might differ every time. Deferred execution provides the facility of query reuse since the query fetches the updated data from the data source each time query results are iterated.
1 2 3 4 | |
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 | |
LINQ expressions that might be used in the following practical sessions:
| Name | Return type | Immediate execution | Deferred execution | Notes |
|---|---|---|---|---|
| Any | bool | ✅ | Determines whether any element of a sequence exists or satisfies a condition. | |
| Average | Single numeric value | ✅ | Computes the average of a sequence of numeric values. | |
| Contains | bool | ✅ | Determines whether a sequence contains a specified element. | |
| Count | int | ✅ | Returns the number of elements in a sequence. | |
| Distinct | IEnumerable |
✅ | Returns distinct elements from a sequence. | |
| First | TSource | ✅ | Returns the first element of a sequence. | |
| FirstOrDefault | TSource? | ✅ | Returns the first element of a sequence, or a default value if no element is found. | |
| GroupBy | IEnumerable |
✅ | Groups the elements of a sequence. | |
| Join | IEnumerable |
✅ | Correlates the elements of two sequences based on matching keys. | |
| Last | TSource | ✅ | Returns the last element of a sequence. | |
| LastOrDefault | TSource? | ✅ | Returns the last element of a sequence, or a default value if no element is found. | |
| Max | Single numeric value | ✅ | Returns the maximum value in a sequence of values. | |
| Min | Single numeric value | ✅ | Returns the minimum value in a sequence of values. | |
| OrderBy | IOrderedEnumerable |
✅ | Sorts the elements of a sequence in ascending order. | |
| OrderByDescending | IOrderedEnumerable |
✅ | Sorts the elements of a sequence in descending order. | |
| Select | IEnumerable |
✅ | Projects each element of a sequence into a new form. | |
| Single | TSource | ✅ | Returns a single, specific element of a sequence. | |
| SingleOrDefault | TSource? | ✅ | Returns a single, specific element of a sequence, or a default value if that element is not found. | |
| Sum | Single numeric value | ✅ | Computes the sum of a sequence of numeric values. | |
| Take | IEnumerable |
✅ | Returns a specified number of contiguous elements from the start of a sequence. | |
| ThenBy | IOrderedEnumerable |
✅ | Performs a subsequent ordering of the elements in a sequence in ascending order. | |
| ThenByDescending | IOrderedEnumerable |
✅ | Performs a subsequent ordering of the elements in a sequence in descending order. | |
| ToList | IList |
✅ | Creates a List |
|
| Where | IEnumerable |
✅ | Filters a sequence of values based on a predicate. |
Tasks¶
Based on the latest project snapshot (apiary-practice-4.zip), the following functionalities should be implemented:
- Create a new model class called
Orderwith the following properties:- Order Date
- Status (New, Approved, Completed)
- Add the
Orderclass to theApiaryContextand create a new migration - Update the database
- Create a new Form for creating Orders
- The order date should be changeable via a DateTimePicker control
- The order status should be set to New during creation
- Create a new (or reuse the existing) listing Form where the orders can be listed and ordered by their
OrderDateproperty.