From 97a29e60f5d861d848b85ef1e8ed8b1988f9ced1 Mon Sep 17 00:00:00 2001 From: Steve Hoag Date: Mon, 12 Dec 2016 09:02:31 -0800 Subject: [PATCH] Updated LINQ topics for C# Concepts section (#1302) * Updated LINQ topics for C# Concepts section Phase one - additional topics will be moved from the Programming Guide later * Fixed build errors * Addressed feedback * Created a LINQ folder and moved the files; updated links * Updated TOC with new path * Updated redirect URLs * Fixed one more redirect --- docs/csharp/linq.md | 25 -- docs/csharp/linq/create-a-nested-group.md | 29 ++ ...ly-specify-predicate-filters-at-runtime.md | 76 +++++ docs/csharp/linq/group-query-results.md | 81 ++++++ .../linq/group-results-by-contiguous-keys.md | 55 ++++ .../handle-exceptions-in-query-expressions.md | 37 +++ ...handle-null-values-in-query-expressions.md | 36 +++ docs/csharp/linq/index.md | 61 ++++ .../linq/join-by-using-composite-keys.md | 43 +++ docs/csharp/linq/linq-in-csharp.md | 43 +++ .../order-the-results-of-a-join-clause.md | 26 ++ ...form-a-subquery-on-a-grouping-operation.md | 31 +++ .../linq/perform-custom-join-operations.md | 47 ++++ docs/csharp/linq/perform-grouped-joins.md | 46 +++ docs/csharp/linq/perform-inner-joins.md | 79 ++++++ docs/csharp/linq/perform-left-outer-joins.md | 36 +++ .../linq/query-a-collection-of-objects.md | 29 ++ docs/csharp/linq/query-expression-basics.md | 178 ++++++++++++ .../linq/return-a-query-from-a-method.md | 27 ++ .../store-the-results-of-a-query-in-memory.md | 34 +++ docs/csharp/linq/write-linq-queries.md | 92 ++++++ .../programming-guide/concepts/linq/index.md | 50 +--- .../how-to-create-a-nested-group.md | 54 +--- ...ly-specify-predicate-filters-at-runtime.md | 107 +------ .../how-to-group-query-results.md | 108 +------ ...how-to-group-results-by-contiguous-keys.md | 74 +---- ...-handle-exceptions-in-query-expressions.md | 65 +---- ...handle-null-values-in-query-expressions.md | 55 +--- .../how-to-join-by-using-composite-keys.md | 78 +----- ...w-to-order-the-results-of-a-join-clause.md | 60 +--- ...form-a-subquery-on-a-grouping-operation.md | 58 +--- .../how-to-perform-custom-join-operations.md | 82 +----- .../how-to-perform-grouped-joins.md | 82 +----- .../how-to-perform-inner-joins.md | 115 +------- .../how-to-perform-left-outer-joins.md | 73 +---- .../how-to-query-a-collection-of-objects.md | 60 +--- .../how-to-return-a-query-from-a-method.md | 58 +--- ...-store-the-results-of-a-query-in-memory.md | 64 +---- .../how-to-write-linq-queries.md | 113 +------- .../linq-query-expressions/index.md | 102 +------ .../query-expression-basics.md | 189 +------------ docs/toc.md | 21 +- .../linq/how-to-create-a-nested-group_1.cs | 57 ++++ ...-specify-predicate-filters-at-runtime_1.cs | 24 ++ ...-specify-predicate-filters-at-runtime_2.cs | 41 +++ .../linq/how-to-group-query-results_1.cs | 88 ++++++ .../linq/how-to-group-query-results_2.cs | 45 +++ .../linq/how-to-group-query-results_3.cs | 40 +++ .../linq/how-to-group-query-results_4.cs | 6 + .../linq/how-to-group-query-results_5.cs | 40 +++ .../linq/how-to-group-query-results_6.cs | 34 +++ .../linq/how-to-group-query-results_7.cs | 46 +++ ...w-to-group-results-by-contiguous-keys_1.cs | 263 ++++++++++++++++++ ...andle-exceptions-in-query-expressions_1.cs | 39 +++ ...andle-exceptions-in-query-expressions_2.cs | 48 ++++ ...ndle-null-values-in-query-expressions_1.cs | 6 + ...ndle-null-values-in-query-expressions_2.cs | 8 + ...to-order-the-results-of-a-join-clause_1.cs | 88 ++++++ ...rm-a-subquery-on-a-grouping-operation_1.cs | 21 ++ ...how-to-perform-custom-join-operations_1.cs | 117 ++++++++ ...how-to-perform-custom-join-operations_2.cs | 67 +++++ .../linq/how-to-perform-grouped-joins_1.cs | 60 ++++ .../linq/how-to-perform-grouped-joins_2.cs | 62 +++++ .../linq/how-to-perform-inner-joins_1.cs | 52 ++++ .../linq/how-to-perform-inner-joins_2.cs | 50 ++++ .../linq/how-to-perform-inner-joins_3.cs | 70 +++++ .../linq/how-to-perform-inner-joins_4.cs | 67 +++++ .../linq/how-to-perform-left-outer-joins_1.cs | 48 ++++ .../how-to-query-a-collection-of-objects_1.cs | 88 ++++++ .../how-to-return-a-query-from-a-method_1.cs | 79 ++++++ ...tore-the-results-of-a-query-in-memory_1.cs | 25 ++ .../linq/how-to-write-linq-queries_1.cs | 21 ++ .../linq/how-to-write-linq-queries_2.cs | 7 + .../linq/how-to-write-linq-queries_3.cs | 2 + .../linq/how-to-write-linq-queries_4.cs | 4 + .../linq/how-to-write-linq-queries_5.cs | 16 ++ .../snippets/csharp/concepts/linq/index_1.cs | 22 ++ .../linq/query-expression-basics_1.cs | 5 + .../linq/query-expression-basics_10.cs | 5 + .../linq/query-expression-basics_11.cs | 3 + .../linq/query-expression-basics_12.cs | 4 + .../linq/query-expression-basics_13.cs | 5 + .../linq/query-expression-basics_14.cs | 16 ++ .../linq/query-expression-basics_15.cs | 4 + .../linq/query-expression-basics_16.cs | 4 + .../linq/query-expression-basics_17.cs | 4 + .../linq/query-expression-basics_18.cs | 9 + .../linq/query-expression-basics_19.cs | 11 + .../linq/query-expression-basics_2.cs | 5 + .../linq/query-expression-basics_3.cs | 5 + .../linq/query-expression-basics_4.cs | 6 + .../linq/query-expression-basics_5.cs | 19 ++ .../linq/query-expression-basics_6.cs | 9 + .../linq/query-expression-basics_7.cs | 29 ++ .../linq/query-expression-basics_8.cs | 7 + .../linq/query-expression-basics_9.cs | 4 + 96 files changed, 3031 insertions(+), 1653 deletions(-) delete mode 100644 docs/csharp/linq.md create mode 100644 docs/csharp/linq/create-a-nested-group.md create mode 100644 docs/csharp/linq/dynamically-specify-predicate-filters-at-runtime.md create mode 100644 docs/csharp/linq/group-query-results.md create mode 100644 docs/csharp/linq/group-results-by-contiguous-keys.md create mode 100644 docs/csharp/linq/handle-exceptions-in-query-expressions.md create mode 100644 docs/csharp/linq/handle-null-values-in-query-expressions.md create mode 100644 docs/csharp/linq/index.md create mode 100644 docs/csharp/linq/join-by-using-composite-keys.md create mode 100644 docs/csharp/linq/linq-in-csharp.md create mode 100644 docs/csharp/linq/order-the-results-of-a-join-clause.md create mode 100644 docs/csharp/linq/perform-a-subquery-on-a-grouping-operation.md create mode 100644 docs/csharp/linq/perform-custom-join-operations.md create mode 100644 docs/csharp/linq/perform-grouped-joins.md create mode 100644 docs/csharp/linq/perform-inner-joins.md create mode 100644 docs/csharp/linq/perform-left-outer-joins.md create mode 100644 docs/csharp/linq/query-a-collection-of-objects.md create mode 100644 docs/csharp/linq/query-expression-basics.md create mode 100644 docs/csharp/linq/return-a-query-from-a-method.md create mode 100644 docs/csharp/linq/store-the-results-of-a-query-in-memory.md create mode 100644 docs/csharp/linq/write-linq-queries.md create mode 100644 samples/snippets/csharp/concepts/linq/how-to-create-a-nested-group_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-dynamically-specify-predicate-filters-at-runtime_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-dynamically-specify-predicate-filters-at-runtime_2.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-group-query-results_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-group-query-results_2.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-group-query-results_3.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-group-query-results_4.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-group-query-results_5.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-group-query-results_6.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-group-query-results_7.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-group-results-by-contiguous-keys_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-handle-exceptions-in-query-expressions_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-handle-exceptions-in-query-expressions_2.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-handle-null-values-in-query-expressions_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-handle-null-values-in-query-expressions_2.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-order-the-results-of-a-join-clause_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-perform-a-subquery-on-a-grouping-operation_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-perform-custom-join-operations_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-perform-custom-join-operations_2.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-perform-grouped-joins_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-perform-grouped-joins_2.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_2.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_3.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_4.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-perform-left-outer-joins_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-query-a-collection-of-objects_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-return-a-query-from-a-method_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-store-the-results-of-a-query-in-memory_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_2.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_3.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_4.cs create mode 100644 samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_5.cs create mode 100644 samples/snippets/csharp/concepts/linq/index_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_1.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_10.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_11.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_12.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_13.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_14.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_15.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_16.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_17.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_18.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_19.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_2.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_3.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_4.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_5.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_6.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_7.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_8.cs create mode 100644 samples/snippets/csharp/concepts/linq/query-expression-basics_9.cs diff --git a/docs/csharp/linq.md b/docs/csharp/linq.md deleted file mode 100644 index 4d103b60e2127..0000000000000 --- a/docs/csharp/linq.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: Language Integrated Query (LINQ) -description: Language Integrated Query (LINQ) -keywords: .NET, .NET Core -ms.date: 06/20/2016 -ms.topic: article -ms.prod: .net -ms.technology: devlang-csharp -ms.devlang: csharp -ms.assetid: 007cc736-f5cf-4919-b99b-0c00ab2814ce ---- - -# 🔧 Language Integrated Query (LINQ) - -> **Note** -> -> This topic hasn’t been written yet! -> -> We welcome your input to help shape the scope and approach. You can track the status and provide input on this -> [issue](https://github.com/dotnet/docs/issues/490) at GitHub. -> -> If you would like to review early drafts and outlines of this topic, please leave a note with your contact information in the issue. -> -> Learn more about how you can contribute on [GitHub](https://github.com/dotnet/docs/blob/master/CONTRIBUTING.md). -> diff --git a/docs/csharp/linq/create-a-nested-group.md b/docs/csharp/linq/create-a-nested-group.md new file mode 100644 index 0000000000000..6e41f08d7998e --- /dev/null +++ b/docs/csharp/linq/create-a-nested-group.md @@ -0,0 +1,29 @@ +--- +title: "Create a nested group" +description: How to create a nested group. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 12/1/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: e9f00708-362e-4d13-98c5-d77549347ba0 +--- +# Create a nested group + +The following example shows how to create nested groups in a LINQ query expression. Each group that is created according to student year or grade level is then further subdivided into groups based on the individuals' names. + +## Example + + > [!NOTE] + > This example contains references to objects that are defined in the sample code in [Query a collection of objects](query-a-collection-of-objects.md). + + [!code-cs[csProgGuideLINQ#24](../../../samples/snippets/csharp/concepts/linq/how-to-create-a-nested-group_1.cs)] + + Note that three nested `foreach` loops are required to iterate over the inner elements of a nested group. + +## See also + [LINQ Query Expressions](index.md) \ No newline at end of file diff --git a/docs/csharp/linq/dynamically-specify-predicate-filters-at-runtime.md b/docs/csharp/linq/dynamically-specify-predicate-filters-at-runtime.md new file mode 100644 index 0000000000000..57f6b0ff93b0f --- /dev/null +++ b/docs/csharp/linq/dynamically-specify-predicate-filters-at-runtime.md @@ -0,0 +1,76 @@ +--- +title: "Dynamically specify predicate filters at runtime" +description: How to dynamically specify predicate filters at runtime. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 12/1/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: 90238470-0767-497c-916c-52d0d16845e0 +--- +# Dynamically specify predicate filters at runtime + +In some cases you do not know until run time how many predicates you have to apply to source elements in the `where` clause. One way to dynamically specify multiple predicate filters is to use the method, as shown in the following example. The example is constructed in two ways. First, the project is run by filtering on values that are provided in the program. Then the project is run again by using input provided at run time. + +## To filter by using the Contains method + +1. Open a new console application and name it `PredicateFilters`. + +2. Copy the `StudentClass` class from [Query a collection of objects](query-a-collection-of-objects.md) and paste it into namespace `PredicateFilters` underneath class `Program`. `StudentClass` provides a list of `Student` objects. + +3. Comment out the `Main` method in `StudentClass`. + +4. Replace class `Program` with the following code. + + [!code-cs[csProgGuideLINQ#26](../../../samples/snippets/csharp/concepts/linq/how-to-dynamically-specify-predicate-filters-at-runtime_1.cs)] + +5. Add the following line to the `Main` method in class `DynamicPredicates`, under the declaration of `ids`. + + ```cs + QueryById(ids); + ``` + +6. Run the project. + +7. The following output is displayed in a console window: + + Garcia: 114 + + O'Donnell: 112 + + Omelchenko: 111 + +8. The next step is to run the project again, this time by using input entered at run time instead of array `ids`. Change `QueryByID(ids)` to `QueryByID(args)` in the `Main` method. + +9. Run the project with the command line arguments `122 117 120 115`. When the project is run, those values become elements of `args`, the parameter of the `Main` method.. + +10. The following output is displayed in a console window: + + Adams: 120 + + Feng: 117 + + Garcia: 115 + + Tucker: 122 + +## To filter by using a switch statement + +1. You can use a `switch` statement to select among predetermined alternative queries. In the following example, `studentQuery` uses a different `where` clause depending on which grade level, or year, is specified at run time. + +2. Copy the following method and paste it into class `DynamicPredicates`. + + [!code-cs[csProgGuideLINQ#27](../../../samples/snippets/csharp/concepts/linq//how-to-dynamically-specify-predicate-filters-at-runtime_2.cs)] + +3. In the `Main` method, replace the call to `QueryByID` with the following call, which sends the first element from the `args` array as its argument: `QueryByYear(args[0])`. + +4. Run the project with a command line argument of an integer value between 1 and 4. + + +## See Also + [LINQ Query Expressions](index.md) + [where clause](../language-reference/keywords/where-clause.md) \ No newline at end of file diff --git a/docs/csharp/linq/group-query-results.md b/docs/csharp/linq/group-query-results.md new file mode 100644 index 0000000000000..bc2a88ded7d92 --- /dev/null +++ b/docs/csharp/linq/group-query-results.md @@ -0,0 +1,81 @@ +--- +title: "Group query results" +description: How to group results. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 12/1/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: 2e4ec27f-06fb-4de7-8973-0189906d4520 +--- +# Group query results + +Grouping is one of the most powerful capabilities of LINQ. The following examples show how to group data in various ways: + +- By a single property. + +- By the first letter of a string property. + +- By a computed numeric range. + +- By Boolean predicate or other expression. + +- By a compound key. + + In addition, the last two queries project their results into a new anonymous type that contains only the student's first and last name. For more information, see the [group clause](../language-reference/keywords/group-clause.md). + +## Example + All the examples in this topic use the following helper classes and data sources. + + [!code-cs[csProgGuideLINQ#15](../../../samples/snippets/csharp/concepts/linq/how-to-group-query-results_1.cs)] + +## Example + The following example shows how to group source elements by using a single property of the element as the group key. In this case the key is a `string`, the student's last name. It is also possible to use a substring for the key. The grouping operation uses the default equality comparer for the type. + + Paste the following method into the `StudentClass` class. Change the calling statement in the `Main` method to `sc.GroupBySingleProperty()`. + + [!code-cs[csProgGuideLINQ#17](../../../samples/snippets/csharp/concepts/linq/how-to-group-query-results_2.cs)] + +## Example + The following example shows how to group source elements by using something other than a property of the object for the group key. In this example, the key is the first letter of the student's last name. + + Paste the following method into the `StudentClass` class. Change the calling statement in the `Main` method to `sc.GroupBySubstring()`. + + [!code-cs[csProgGuideLINQ#18](../../../samples/snippets/csharp/concepts/linq/how-to-group-query-results_3.cs)] + +## Example + The following example shows how to group source elements by using a numeric range as a group key. The query then projects the results into an anonymous type that contains only the first and last name and the percentile range to which the student belongs. An anonymous type is used because it is not necessary to use the complete `Student` object to display the results. `GetPercentile` is a helper function that calculates a percentile based on the student's average score. The method returns an integer between 0 and 10. + + [!code-cs[csProgGuideLINQ#50](../../../samples/snippets/csharp/concepts/linq/how-to-group-query-results_4.cs)] + + Paste the following method into the `StudentClass` class. Change the calling statement in the `Main` method to `sc.GroupByRange()`. + + [!code-cs[csProgGuideLINQ#19](../../../samples/snippets/csharp/concepts/linq/how-to-group-query-results_5.cs)] + +## Example + The following example shows how to group source elements by using a Boolean comparison expression. In this example, the Boolean expression tests whether a student's average exam score is greater than 75. As in previous examples, the results are projected into an anonymous type because the complete source element is not needed. Note that the properties in the anonymous type become properties on the `Key` member and can be accessed by name when the query is executed. + + Paste the following method into the `StudentClass` class. Change the calling statement in the `Main` method to `sc.GroupByBoolean()`. + + [!code-cs[csProgGuideLINQ#20](../../../samples/snippets/csharp/concepts/linq/how-to-group-query-results_6.cs)] + +## Example + The following example shows how to use an anonymous type to encapsulate a key that contains multiple values. In this example, the first key value is the first letter of the student's last name. The second key value is a Boolean that specifies whether the student scored over 85 on the first exam. You can order the groups by any property in the key. + + Paste the following method into the `StudentClass` class. Change the calling statement in the `Main` method to `sc.GroupByCompositeKey()`. + + [!code-cs[csProgGuideLINQ#21](../../../samples/snippets/csharp/concepts/linq/how-to-group-query-results_7.cs)] + +## See also + + + [LINQ Query Expressions](index.md) + [group clause](../language-reference/keywords/group-clause.md) + [Anonymous Types](../programming-guide/classes-and-structs/anonymous-types.md) + [Perform a Subquery on a Grouping Operation](perform-a-subquery-on-a-grouping-operation.md) + [Create a Nested Group](create-a-nested-group.md) + [Grouping Data](../programming-guide/concepts/linq/grouping-data.md) \ No newline at end of file diff --git a/docs/csharp/linq/group-results-by-contiguous-keys.md b/docs/csharp/linq/group-results-by-contiguous-keys.md new file mode 100644 index 0000000000000..5609aa841bf41 --- /dev/null +++ b/docs/csharp/linq/group-results-by-contiguous-keys.md @@ -0,0 +1,55 @@ +--- +title: "Group results by contiguous keys" +description: How to group results by contiguous keys. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 12/1/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: cbda9c08-151b-4c9e-82f7-c3d7f3dac66b +--- +# Group results by contiguous keys + +The following example shows how to group elements into chunks that represent subsequences of contiguous keys. For example, assume that you are given the following sequence of key-value pairs: + +|Key|Value| +|---------|-----------| +|A|We| +|A|think| +|A|that| +|B|Linq| +|C|is| +|A|really| +|B|cool| +|B|!| + + The following groups will be created in this order: + +1. We, think, that + +2. Linq + +3. is + +4. really + +5. cool, ! + + The solution is implemented as an extension method that is thread-safe and that returns its results in a streaming manner. In other words, it produces its groups as it moves through the source sequence. Unlike the `group` or `orderby` operators, it can begin returning groups to the caller before all of the sequence has been read. + + Thread-safety is accomplished by making a copy of each group or chunk as the source sequence is iterated, as explained in the source code comments. If the source sequence has a large sequence of contiguous items, the common language runtime may throw an . + +## Example + The following example shows both the extension method and the client code that uses it. + + [!code-cs[cscsrefContiguousGroups#1](../../../samples/snippets/csharp/concepts/linq/how-to-group-results-by-contiguous-keys_1.cs)] + + To use the extension method in your project, copy the `MyExtensions` static class to a new or existing source code file and if it is required, add a `using` directive for the namespace where it is located. + +## See also + [LINQ Query Expressions](index.md) + \ No newline at end of file diff --git a/docs/csharp/linq/handle-exceptions-in-query-expressions.md b/docs/csharp/linq/handle-exceptions-in-query-expressions.md new file mode 100644 index 0000000000000..c6aa346aabb14 --- /dev/null +++ b/docs/csharp/linq/handle-exceptions-in-query-expressions.md @@ -0,0 +1,37 @@ +--- +title: "Handle exceptions in query expressions" +description: How to handle exceptions in query expressions. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 12/1/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: 2bf0c397-13fb-4f68-bc2b-531c6c88a167 +--- +# Handle exceptions in query expressions + +It is possible to call any method in the context of a query expression. However, we recommend that you avoid calling any method in a query expression that can create a side effect such as modifying the contents of the data source or throwing an exception. This example shows how to avoid raising exceptions when you call methods in a query expression without violating the general .NET Framework guidelines on exception handling. Those guidelines state that it is acceptable to catch a specific exception when you understand why it will be thrown in a given context. For more information, see [Best Practices for Exceptions](http://msdn.microsoft.com/library/f06da765-235b-427a-bfb6-47cd219af539). + + The final example shows how to handle those cases when you must throw an exception during execution of a query. + +## Example + + The following example shows how to move exception handling code outside a query expression. This is only possible when the method does not depend on any variables local to the query. + + [!code-cs[csProgGuideLINQ#10](../../../samples/snippets/csharp/concepts/linq/how-to-handle-exceptions-in-query-expressions_1.cs)] + +## Example + + In some cases, the best response to an exception that is thrown from within a query might be to stop the query execution immediately. The following example shows how to handle exceptions that might be thrown from inside a query body. Assume that `SomeMethodThatMightThrow` can potentially cause an exception that requires the query execution to stop. + + Note that the `try` block encloses the `foreach` loop, and not the query itself. This is because the `foreach` loop is the point at which the query is actually executed. For more information, see [Introduction to LINQ queries](../programming-guide/concepts/linq/introduction-to-linq-queries.md). + + [!code-cs[csProgGuideLINQ#12](../../../samples/snippets/csharp/concepts/linq/how-to-handle-exceptions-in-query-expressions_2.cs)] + + +## See Also + [LINQ query expressions](index.md) \ No newline at end of file diff --git a/docs/csharp/linq/handle-null-values-in-query-expressions.md b/docs/csharp/linq/handle-null-values-in-query-expressions.md new file mode 100644 index 0000000000000..e079922af6f49 --- /dev/null +++ b/docs/csharp/linq/handle-null-values-in-query-expressions.md @@ -0,0 +1,36 @@ +--- +title: "Handle null values in query expressions" +description: How to handle null values in query expressions. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 12/1/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: ac63ae8b-724d-4251-9334-528f4e884ae7 +--- +# Handle null values in query expressions + +This example shows how to handle possible null values in source collections. An object collection such as an can contain elements whose value is [null](../language-reference/keywords/null.md). If a source collection is null or contains an element whose value is null, and your query does not handle null values, a will be thrown when you execute the query. + +## Example + + You can code defensively to avoid a null reference exception as shown in the following example: + + [!code-cs[csProgGuideLINQ#82](../../../samples/snippets/csharp/concepts/linq/how-to-handle-null-values-in-query-expressions_1.cs)] + + In the previous example, the `where` clause filters out all null elements in the categories sequence. This technique is independent of the null check in the join clause. The conditional expression with null in this example works because `Products.CategoryID` is of type `int?` which is shorthand for `Nullable`. + +## Example + + In a join clause, if only one of the comparison keys is a nullable value type, you can cast the other to a nullable type in the query expression. In the following example, assume that `EmployeeID` is a column that contains values of type `int?`: + + [!code-cs[csProgGuideLINQ#83](../../../samples/snippets/csharp/concepts/linq/how-to-handle-null-values-in-query-expressions_2.cs)] + +## See also + + [LINQ query expressions](index.md) + [Nullable types](../programming-guide/nullable-types/index.md) \ No newline at end of file diff --git a/docs/csharp/linq/index.md b/docs/csharp/linq/index.md new file mode 100644 index 0000000000000..03db1b3edddcb --- /dev/null +++ b/docs/csharp/linq/index.md @@ -0,0 +1,61 @@ +--- +title: Language Integrated Query (LINQ) +description: Introduces Language Integrated Query (LINQ) in C# +keywords: .NET, .NET Core +<<<<<<< HEAD +ms.date: 06/20/2016 +======= +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 11/30/2016 +>>>>>>> Updated LINQ topics for C# Concepts section +ms.topic: article +ms.prod: .net +ms.technology: devlang-csharp +ms.devlang: csharp +ms.assetid: 007cc736-f5cf-4919-b99b-0c00ab2814ce +--- + +# Language Integrated Query (LINQ) + +Language-Integrated Query (LINQ) is the name for a set of technologies based on the integration of query capabilities directly into the C# language. 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, events. + +For a developer who writes queries, the most visible "language-integrated" part of LINQ is the query expression. Query expressions are written in a declarative *query syntax*. By using query syntax, you can perform filtering, ordering, and grouping operations on data sources with a minimum of code. You use the same basic query expression patterns to query and transform data in SQL databases, ADO .NET Datasets, XML documents and streams, and .NET collections. + +The following example shows the complete query operation. The complete operation includes creating a data source, defining the query expression, and executing the query in a `foreach` statement. + +[!code-cs[csProgGuideLINQ#11](../../../samples/snippets/csharp/concepts/linq/index_1.cs)] + +## Query expression overview + +- Query expressions can be used to query and to 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 are easy to master because they use many familiar C# language constructs. + +- The variables in a query expression are all strongly typed, although in many cases you do not have to provide the type explicitly because the compiler can infer it. For more information, see [Type relationships in LINQ query operations](../programming-guide/concepts/linq/type-relationships-in-linq-query-operations.md). + +- A query is not executed until you iterate over the query variable, for example, in a `foreach` statement. For more information, see [Introduction to LINQ queries](../programming-guide/concepts/linq/introduction-to-linq-queries.md). + +- At compile time, query expressions are converted to Standard Query Operator method calls according to the rules set forth in the C# specification. Any query that can be expressed by using query syntax can also be expressed by using method syntax. However, in most cases query syntax is more readable and concise. For more information, see [C# language specification](../language-reference/language-specification.md) and [Standard query operators overview](../programming-guide/concepts/linq/standard-query-operators-overview.md). + +- As a rule when you write LINQ queries, we recommend that you use query syntax whenever possible and method syntax whenever necessary. There is no semantic or performance difference between the two different forms. Query expressions are often more readable than equivalent expressions written in method syntax. + +- Some query operations, such as or , have no equivalent query expression clause and must therefore be expressed as a method call. Method syntax can be combined with query syntax in various ways. For more information, see [Query syntax and method syntax in LINQ](../programming-guide/concepts/linq/query-syntax-and-method-syntax-in-linq.md). + +- Query expressions can be compiled to expression trees or to delegates, depending on the type that the query is applied to. queries are compiled to delegates. and queries are compiled to expression trees. For more information, see [Expression trees](../expression-trees.md). + +## Next steps + +To learn more details about LINQ, start by becoming familiar with some basic concepts in [Query expression basics](query-expression-basics.md), and then read the documentation for the LINQ technology in which you are interested: +- XML documents: [LINQ to XML](../programming-guide/concepts/linq/linq-to-xml.md) + +- ADO.NET Entity Framework: [LINQ to entities](http://msdn.microsoft.com/library/641f9b68-9046-47a1-abb0-1c8eaeda0e2d) + +- .NET collections, files, strings and so on: [LINQ to objects](../programming-guide/concepts/linq/linq-to-objects.md) + +To gain a deeper understanding of LINQ in general, see [LINQ in C#](linq-in-csharp.md). + +To start working with LINQ in C#, see the tutorial [Working with LINQ](../tutorials/working-with-linq.md). + + diff --git a/docs/csharp/linq/join-by-using-composite-keys.md b/docs/csharp/linq/join-by-using-composite-keys.md new file mode 100644 index 0000000000000..e3431e0c0a414 --- /dev/null +++ b/docs/csharp/linq/join-by-using-composite-keys.md @@ -0,0 +1,43 @@ +--- +title: "Join by using composite keys" +description: How to join by using composite keys. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 12/1/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: da70b54d-3213-45eb-8437-fbe75cbcf935 +--- +# Join by using composite keys + +This example shows how to perform join operations in which you want to use more than one key to define a match. This is accomplished by using a composite key. You create a composite key as an anonymous type or named typed with the values that you want to compare. If the query variable will be passed across method boundaries, use a named type that overrides and for the key. The names of the properties, and the order in which they occur, must be identical in each key. + +## Example + The following example demonstrates how to use a composite key to join data from three tables: + +```cs +var query = from o in db.Orders + from p in db.Products + join d in db.OrderDetails + on new {o.OrderID, p.ProductID} equals new {d.OrderID, d.ProductID} into details + from d in details + select new {o.OrderID, p.ProductID, d.UnitPrice}; +``` + + Type inference on composite keys depends on the names of the properties in the keys, and the order in which they occur. If the properties in the source sequences do not have the same names, you must assign new names in the keys. For example, if the `Orders` table and `OrderDetails` table each used different names for their columns, you could create composite keys by assigning identical names in the anonymous types: + +```cs +join...on new {Name = o.CustomerName, ID = o.CustID} equals + new {Name = d.CustName, ID = d.CustID } +``` + + Composite keys can be also used in a `group` clause. + +## See also + [LINQ query expressions](index.md) + [join clause](../language-reference/keywords/join-clause.md) + [group clause](../language-reference/keywords/group-clause.md) \ No newline at end of file diff --git a/docs/csharp/linq/linq-in-csharp.md b/docs/csharp/linq/linq-in-csharp.md new file mode 100644 index 0000000000000..f06e7679414e8 --- /dev/null +++ b/docs/csharp/linq/linq-in-csharp.md @@ -0,0 +1,43 @@ +--- +title: "LINQ in C#" +description: Links to topics that provide more detailed information about LINQ. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 11/30/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: 8eb3284f-0ab9-4cad-9216-2da58d9761a5 +--- +# LINQ in C# +This section contains links to topics that provide more detailed information about LINQ. + +## In this section + [Introduction to LINQ queries](../programming-guide/concepts/linq/introduction-to-linq-queries.md) + Describes the three parts of the basic LINQ query operation that are common across all languages and data sources. + + [LINQ and generic types](../programming-guide/concepts/linq/linq-and-generic-types.md) + Provides a brief introduction to generic types as they are used in LINQ. + + [Data transformations with LINQ](../programming-guide/concepts/linq/data-transformations-with-linq.md) + Describes the various ways that you can transform data retrieved in queries. + + [Type relationships in LINQ query operations](../programming-guide/concepts/linq/type-relationships-in-linq-query-operations.md) + Describes how types are preserved and/or transformed in the three parts of a LINQ query operation + + [Query syntax and method syntax in LINQ](../programming-guide/concepts/linq/query-syntax-and-method-syntax-in-linq.md) + Compares method syntax and query syntax as two ways to express a LINQ query. + + [C# features that support LINQ](../programming-guide/concepts/linq/features-that-support-linq.md) + Describes the language constructs in C# that support LINQ. + +## Related sections + [LINQ query expressions](../programming-guide/linq-query-expressions/index.md) + Includes an overview of queries in LINQ and provides links to additional resources. + + [Standard query operators overview](../programming-guide/concepts/linq/standard-query-operators-overview.md) + Introduces the standard methods used in LINQ. + \ No newline at end of file diff --git a/docs/csharp/linq/order-the-results-of-a-join-clause.md b/docs/csharp/linq/order-the-results-of-a-join-clause.md new file mode 100644 index 0000000000000..14dd1babe4660 --- /dev/null +++ b/docs/csharp/linq/order-the-results-of-a-join-clause.md @@ -0,0 +1,26 @@ +--- +title: "Order the results of a join clause" +description: How to order the results of a join clause. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 12/1/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: a7458901-1201-4c25-b8d9-c04ca52e0eb9 +--- +# Order the results of a join clause +This example shows how to order the results of a join operation. Note that the ordering is performed after the join. Although you can use an `orderby` clause with one or more of the source sequences before the join, generally we do not recommend it. Some LINQ providers might not preserve that ordering after the join. + +## Example + This query creates a group join, and then sorts the groups based on the category element, which is still in scope. Inside the anonymous type initializer, a sub-query orders all the matching elements from the products sequence. + + [!code-cs[csProgGuideLINQ#81](../../../samples/snippets/csharp/concepts/linq/how-to-order-the-results-of-a-join-clause_1.cs)] + +## See also + [LINQ query expressions](index.md) + [orderby clause](../language-reference/keywords/orderby-clause.md) + [join clause](../language-reference/keywords/join-clause.md) \ No newline at end of file diff --git a/docs/csharp/linq/perform-a-subquery-on-a-grouping-operation.md b/docs/csharp/linq/perform-a-subquery-on-a-grouping-operation.md new file mode 100644 index 0000000000000..25c891ea39c79 --- /dev/null +++ b/docs/csharp/linq/perform-a-subquery-on-a-grouping-operation.md @@ -0,0 +1,31 @@ +--- +title: "Perform a subquery on a grouping operation" +description: How to perform a subquery on a grouping operation. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 12/1/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: d75a588e-9b6f-4f37-b195-f99ec8503855 +--- +# Perform a subquery on a grouping operation + +This topic shows two different ways to create a query that orders the source data into groups, and then performs a subquery over each group individually. The basic technique in each example is to group the source elements by using a *continuation* named `newGroup`, and then generating a new subquery against `newGroup`. This subquery is run against each new group that is created by the outer query. Note that in this particular example the final output is not a group, but a flat sequence of anonymous types. + + For more information about how to group, see [group clause](../language-reference/keywords/group-clause.md). + + For more information about continuations, see [into](../language-reference/keywords/into.md). The following example uses an in-memory data structure as the data source, but the same principles apply for any kind of LINQ data source. + +## Example + + > [!NOTE] + > This example contains references to objects that are defined in the sample code in [Query a collection of objects](query-a-collection-of-objects.md). + + [!code-cs[csProgGuideLINQ#23](../../../samples/snippets/csharp/concepts/linq/how-to-perform-a-subquery-on-a-grouping-operation_1.cs)] + +## See also + [LINQ Query Expressions](index.md) \ No newline at end of file diff --git a/docs/csharp/linq/perform-custom-join-operations.md b/docs/csharp/linq/perform-custom-join-operations.md new file mode 100644 index 0000000000000..a7d6c09ea3a9b --- /dev/null +++ b/docs/csharp/linq/perform-custom-join-operations.md @@ -0,0 +1,47 @@ +--- +title: "Perform custom join operations" +description: How to perform custom join operations. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 12/1/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: 56a2a4a5-7299-497d-b3c3-23c848678911 +--- +# Perform custom join operations + +This example shows how to perform join operations that are not possible with the `join` clause. In a query expression, the `join` clause is limited to, and optimized for, equijoins, which are by far the most common type of join operation. When performing an equijoin, you will probably always get the best performance by using the `join` clause. + + However, the `join` clause cannot be used in the following cases: + +- When the join is predicated on an expression of inequality (a non-equijoin). + +- When the join is predicated on more than one expression of equality or inequality. + +- When you have to introduce a temporary range variable for the right side (inner) sequence before the join operation. + + To perform joins that are not equijoins, you can use multiple `from` clauses to introduce each data source independently. You then apply a predicate expression in a `where` clause to the range variable for each source. The expression also can take the form of a method call. + +> [!NOTE] +> Do not confuse this kind of custom join operation with the use of multiple `from` clauses to access inner collections. For more information, see [join clause](../language-reference/keywords/join-clause.md). + +## Example + The first method in the following example shows a simple cross join. Cross joins must be used with caution because they can produce very large result sets. However, they can be useful in some scenarios for creating source sequences against which additional queries are run. + + The second method produces a sequence of all the products whose category ID is listed in the category list on the left side. Note the use of the `let` clause and the `Contains` method to create a temporary array. It also is possible to create the array before the query and eliminate the first `from` clause. + + [!code-cs[csProgGuideLINQ#64](../../../samples/snippets/csharp/concepts/linq/how-to-perform-custom-join-operations_1.cs)] + +## Example + In the following example, the query must join two sequences based on matching keys that, in the case of the inner (right side) sequence, cannot be obtained prior to the join clause itself. If this join were performed with a `join` clause, then the `Split` method would have to be called for each element. The use of multiple `from` clauses enables the query to avoid the overhead of the repeated method call. However, since `join` is optimized, in this particular case it might still be faster than using multiple `from` clauses. The results will vary depending primarily on how expensive the method call is. + + [!code-cs[csProgGuideLINQ#13](../../../samples/snippets/csharp/concepts/linq/how-to-perform-custom-join-operations_2.cs)] + +## See also + [LINQ query expressions](index.md) + [join clause](../language-reference/keywords/join-clause.md) + [Order the results of a join clause](order-the-results-of-a-join-clause.md) \ No newline at end of file diff --git a/docs/csharp/linq/perform-grouped-joins.md b/docs/csharp/linq/perform-grouped-joins.md new file mode 100644 index 0000000000000..0dde48fff8ea3 --- /dev/null +++ b/docs/csharp/linq/perform-grouped-joins.md @@ -0,0 +1,46 @@ +--- +title: "Perform grouped joins" +description: How to perform grouped joins. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 12/1/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: 9667daf9-a5fd-4b43-a5c4-a9c2b744000e +--- +# Perform grouped joins + +The group join is useful for producing hierarchical data structures. It pairs each element from the first collection with a set of correlated elements from the second collection. + + For example, a class or a relational database table named `Student` might contain two fields: `Id` and `Name`. A second class or relational database table named `Course` might contain two fields: `StudentId` and `CourseTitle`. A group join of these two data sources, based on matching `Student.Id` and `Course.StudentId`, would group each `Student` with a collection of `Course` objects (which might be empty). + +> [!NOTE] +> Each element of the first collection appears in the result set of a group join regardless of whether correlated elements are found in the second collection. In the case where no correlated elements are found, the sequence of correlated elements for that element is empty. The result selector therefore has access to every element of the first collection. This differs from the result selector in a non-group join, which cannot access elements from the first collection that have no match in the second collection. + + The first example in this topic shows you how to perform a group join. The second example shows you how to use a group join to create XML elements. + +## Example + +### Group join example + The following example performs a group join of objects of type `Person` and `Pet` based on the `Person` matching the `Pet.Owner` property. Unlike a non-group join, which would produce a pair of elements for each match, the group join produces only one resulting object for each element of the first collection, which in this example is a `Person` object. The corresponding elements from the second collection, which in this example are `Pet` objects, are grouped into a collection. Finally, the result selector function creates an anonymous type for each match that consists of `Person.FirstName` and a collection of `Pet` objects. + + [!code-cs[CsLINQProgJoining#5](../../../samples/snippets/csharp/concepts/linq/how-to-perform-grouped-joins_1.cs)] + +## Example + +### Group join to create XML example + Group joins are ideal for creating XML by using LINQ to XML. The following example is similar to the previous example except that instead of creating anonymous types, the result selector function creates XML elements that represent the joined objects. + + [!code-cs[CsLINQProgJoining#6](../../../samples/snippets/csharp/concepts/linq/how-to-perform-grouped-joins_2.cs)] + +## See also + + + [Perform inner joins](perform-inner-joins.md) + [Perform left outer joins](perform-left-outer-joins.md) + [Anonymous types](../programming-guide/classes-and-structs/anonymous-types.md) + \ No newline at end of file diff --git a/docs/csharp/linq/perform-inner-joins.md b/docs/csharp/linq/perform-inner-joins.md new file mode 100644 index 0000000000000..de1693c3fb154 --- /dev/null +++ b/docs/csharp/linq/perform-inner-joins.md @@ -0,0 +1,79 @@ +--- +title: "Perform inner joins" +description: How to perform inner joins. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 12/1/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: 45bceed6-f549-4114-a9b1-b44feb497742 +--- +# Perform inner joins + +In relational database terms, an *inner join* produces a result set in which each element of the first collection appears one time for every matching element in the second collection. If an element in the first collection has no matching elements, it does not appear in the result set. The method, which is called by the `join` clause in C#, implements an inner join. + + This topic shows you how to perform four variations of an inner join: + +- A simple inner join that correlates elements from two data sources based on a simple key. + +- An inner join that correlates elements from two data sources based on a *composite* key. A composite key, which is a key that consists of more than one value, enables you to correlate elements based on more than one property. + +- A *multiple join* in which successive join operations are appended to each other. + +- An inner join that is implemented by using a group join. + +## Example + +## Simple key join example + The following example creates two collections that contain objects of two user-defined types, `Person` and `Pet`. The query uses the `join` clause in C# to match `Person` objects with `Pet` objects whose `Owner` is that `Person`. The `select` clause in C# defines how the resulting objects will look. In this example the resulting objects are anonymous types that consist of the owner's first name and the pet's name. + + [!code-cs[CsLINQProgJoining#1](../../../samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_1.cs)] + + Note that the `Person` object whose `LastName` is "Huff" does not appear in the result set because there is no `Pet` object that has `Pet.Owner` equal to that `Person`. + +## Example + +## Composite key join example + Instead of correlating elements based on just one property, you can use a composite key to compare elements based on multiple properties. To do this, specify the key selector function for each collection to return an anonymous type that consists of the properties you want to compare. If you label the properties, they must have the same label in each key's anonymous type. The properties must also appear in the same order. + + The following example uses a list of `Employee` objects and a list of `Student` objects to determine which employees are also students. Both of these types have a `FirstName` and a `LastName` property of type . The functions that create the join keys from each list's elements return an anonymous type that consists of the `FirstName` and `LastName` properties of each element. The join operation compares these composite keys for equality and returns pairs of objects from each list where both the first name and the last name match. + + [!code-cs[CsLINQProgJoining#2](../../../samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_2.cs)] + +## Example + +## Multiple join example + Any number of join operations can be appended to each other to perform a multiple join. Each `join` clause in C# correlates a specified data source with the results of the previous join. + + The following example creates three collections: a list of `Person` objects, a list of `Cat` objects, and a list of `Dog` objects. + + The first `join` clause in C# matches people and cats based on a `Person` object matching `Cat.Owner`. It returns a sequence of anonymous types that contain the `Person` object and `Cat.Name`. + + The second `join` clause in C# correlates the anonymous types returned by the first join with `Dog` objects in the supplied list of dogs, based on a composite key that consists of the `Owner` property of type `Person`, and the first letter of the animal's name. It returns a sequence of anonymous types that contain the `Cat.Name` and `Dog.Name` properties from each matching pair. Because this is an inner join, only those objects from the first data source that have a match in the second data source are returned. + + [!code-cs[CsLINQProgJoining#3](../../../samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_3.cs)] + +## Example + +## Inner join by using grouped join example + The following example shows you how to implement an inner join by using a group join. + + In `query1`, the list of `Person` objects is group-joined to the list of `Pet` objects based on the `Person` matching the `Pet.Owner` property. The group join creates a collection of intermediate groups, where each group consists of a `Person` object and a sequence of matching `Pet` objects. + + By adding a second `from` clause to the query, this sequence of sequences is combined (or flattened) into one longer sequence. The type of the elements of the final sequence is specified by the `select` clause. In this example, that type is an anonymous type that consists of the `Person.FirstName` and `Pet.Name` properties for each matching pair. + + The result of `query1` is equivalent to the result set that would have been obtained by using the `join` clause without the `into` clause to perform an inner join. The `query2` variable demonstrates this equivalent query. + + [!code-cs[CsLINQProgJoining#4](../../../samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_4.cs)] + +## See also + + + [Perform grouped joins](perform-grouped-joins.md) + [Perform left outer joins](perform-left-outer-joins.md) + [Anonymous types](../programming-guide/classes-and-structs/anonymous-types.md) + \ No newline at end of file diff --git a/docs/csharp/linq/perform-left-outer-joins.md b/docs/csharp/linq/perform-left-outer-joins.md new file mode 100644 index 0000000000000..f434634d3e99a --- /dev/null +++ b/docs/csharp/linq/perform-left-outer-joins.md @@ -0,0 +1,36 @@ +--- +title: "Perform left outer joins" +description: How to perform left outer joins. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 12/1/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: f542cee6-3169-4dcf-a631-3a6a79ccd473 +--- +# Perform left outer joins +A left outer join is a join in which each element of the first collection is returned, regardless of whether it has any correlated elements in the second collection. You can use LINQ to perform a left outer join by calling the method on the results of a group join. + +## Example + The following example demonstrates how to use the method on the results of a group join to perform a left outer join. + + The first step in producing a left outer join of two collections is to perform an inner join by using a group join. (See [Perform inner joins](perform-inner-joins.md) for an explanation of this process.) In this example, the list of `Person` objects is inner-joined to the list of `Pet` objects based on a `Person` object that matches `Pet.Owner`. + + The second step is to include each element of the first (left) collection in the result set even if that element has no matches in the right collection. This is accomplished by calling on each sequence of matching elements from the group join. In this example, is called on each sequence of matching `Pet` objects. The method returns a collection that contains a single, default value if the sequence of matching `Pet` objects is empty for any `Person` object, thereby ensuring that each `Person` object is represented in the result collection. + +> [!NOTE] +> The default value for a reference type is `null`; therefore, the example checks for a null reference before accessing each element of each `Pet` collection. + + [!code-cs[CsLINQProgJoining#7](../../../samples/snippets/csharp/concepts/linq/how-to-perform-left-outer-joins_1.cs)] + +## See also + + + [Perform inner joins](perform-inner-joins.md) + [Perform grouped joins](perform-grouped-joins.md) + [Anonymous types](../programming-guide/classes-and-structs/anonymous-types.md) + \ No newline at end of file diff --git a/docs/csharp/linq/query-a-collection-of-objects.md b/docs/csharp/linq/query-a-collection-of-objects.md new file mode 100644 index 0000000000000..f6b07f712155c --- /dev/null +++ b/docs/csharp/linq/query-a-collection-of-objects.md @@ -0,0 +1,29 @@ +--- +title: "Query a collection of objects" +description: How query collections. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 11/30/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: 87a76f8a-0b58-4791-90ea-2fe0a30416c9 +--- +# Query a collection of objects +This example shows how to perform a simple query over a list of `Student` objects. Each `Student` object contains some basic information about the student, and a list that represents the student's scores on four examinations. + + This application serves as the framework for many other examples in this section that use the same `students` data source. + +## Example + The following query returns the students who received a score of 90 or greater on their first exam. + + [!code-cs[csProgGuideLINQ#15](../../../samples/snippets/csharp/concepts/linq/how-to-query-a-collection-of-objects_1.cs)] + + This query is intentionally simple to enable you to experiment. For example, you can try more conditions in the `where` clause, or use an `orderby` clause to sort the results. + + +## See also + [LINQ Query Expressions](index.md) \ No newline at end of file diff --git a/docs/csharp/linq/query-expression-basics.md b/docs/csharp/linq/query-expression-basics.md new file mode 100644 index 0000000000000..eb43a4db6c079 --- /dev/null +++ b/docs/csharp/linq/query-expression-basics.md @@ -0,0 +1,178 @@ +--- +title: "Query expression basics" +description: Introduces concepts related to query expressions +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 11/30/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: 027db1f8-346f-44d2-a16e-043fcea3a4e0 +--- +# Query expression basics + +## What is a query and what does it do? + + A *query* is a set of instructions that describes what data to retrieve from a given data source (or sources) and what shape and organization the returned data should have. A query is distinct from the results that it produces. + + Generally, the source data is organized logically as a sequence of elements of the same kind. For example, a SQL database table contains a sequence of rows. In an XML file, there is a "sequence" of XML elements (although these are organized hierarchically in a tree structure). An in-memory collection contains a sequence of objects. + + From an application's viewpoint, the specific type and structure of the original source data is not important. The application always sees the source data as an or collection. For example, in LINQ to XML, the source data is made visible as an `IEnumerable`\<>. + + Given this source sequence, a query may do one of three things: + +- Retrieve a subset of the elements to produce a new sequence without modifying the individual elements. The query may then sort or group the returned sequence in various ways, as shown in the following example (assume `scores` is an `int[]`): + + [!code-cs[csrefQueryExpBasics#45](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_1.cs)] + +- Retrieve a sequence of elements as in the previous example but transform them to a new type of object. For example, a query may retrieve only the last names from certain customer records in a data source. Or it may retrieve the complete record and then use it to construct another in-memory object type or even XML data before generating the final result sequence. The following example shows a projection from an `int` to a `string`. Note the new type of `highScoresQuery`. + + [!code-cs[csrefQueryExpBasics#46](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_2.cs)] + +- Retrieve a singleton value about the source data, such as: + + - The number of elements that match a certain condition. + + - The element that has the greatest or least value. + + - The first element that matches a condition, or the sum of particular values in a specified set of elements. For example, the following query returns the number of scores greater than 80 from the `scores` integer array: + + [!code-cs[csrefQueryExpBasics#47](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_3.cs)] + + In the previous example, note the use of parentheses around the query expression before the call to the `Count` method. You can also express this by using a new variable to store the concrete result. This technique is more readable because it keeps the variable that stores the query separate from the query that stores a result. + + [!code-cs[csrefQueryExpBasics#48](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_4.cs)] + + In the previous example, the query is executed in the call to `Count`, because `Count` must iterate over the results in order to determine the number of elements returned by `highScoresQuery`. + +## What is a query expression? + + A *query expression* is a query expressed in query syntax. A query expression is a first-class language construct. It is just like any other expression and can be used in any context in which a C# expression is valid. A query expression consists of a set of clauses written in a declarative syntax similar to SQL or XQuery. Each clause in turn contains one or more C# expressions, and these expressions may themselves be either a query expression or contain a query expression. + + A query expression must begin with a [from](../language-reference/keywords/from-clause.md) clause and must end with a [select](../language-reference/keywords/select-clause.md) or [group](../language-reference/keywords/group-clause.md) clause. Between the first `from` clause and the last `select` or `group` clause, it can contain one or more of these optional clauses: [where](../language-reference/keywords/where-clause.md), [orderby](../language-reference/keywords/orderby-clause.md), [join](../language-reference/keywords/join-clause.md), [let](../language-reference/keywords/let-clause.md) and even additional [from](../language-reference/keywords/from-clause.md) clauses. You can also use the [into](../language-reference/keywords/into.md) keyword to enable the result of a `join` or `group` clause to serve as the source for additional query clauses in the same query expression. + +### Query variable + + In LINQ, a query variable is any variable that stores a *query* instead of the *results* of a query. More specifically, a query variable is always an enumerable type that will produce a sequence of elements when it is iterated over in a `foreach` statement or a direct call to its `IEnumerator.MoveNext` method. + + The following code example shows a simple query expression with one data source, one filtering clause, one ordering clause, and no transformation of the source elements. The `select` clause ends the query. + + [!code-cs[csrefQueryExpBasics#49](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_5.cs)] + + In the previous example, `scoreQuery` is a *query variable,* which is sometimes referred to as just a *query*. The query variable stores no actual result data, which is produced in the `foreach` loop. And when the `foreach` statement executes, the query results are not returned through the query variable `scoreQuery`. Rather, they are returned through the iteration variable `testScore`. The `scoreQuery` variable can be iterated in a second `foreach` loop. It will produce the same results as long as neither it nor the data source has been modified. + + A query variable may store a query that is expressed in query syntax or method syntax, or a combination of the two. In the following examples, both `queryMajorCities` and `queryMajorCities2` are query variables: + + [!code-cs[csrefQueryExpBasics#50](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_6.cs)] + + On the other hand, the following two examples show variables that are not query variables even through each is initialized with a query. They are not query variables because they store results: + + [!code-cs[csrefQueryExpBasics#51](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_7.cs)] + + For more information about the different ways to express queries, see [Query syntax and method syntax in LINQ](../programming-guide/concepts/linq/query-syntax-and-method-syntax-in-linq.md). + +#### Explicit and implicit typing of query variables + + This documentation usually provides the explicit type of the query variable in order to show the type relationship between the query variable and the [select clause](../language-reference/keywords/select-clause.md). However, you can also use the [var](../language-reference/keywords/var.md) keyword to instruct the compiler to infer the type of a query variable (or any other local variable) at compile time. For example, the query example that was shown previously in this topic can also be expressed by using implicit typing: + + [!code-cs[csrefQueryExpBasics#52](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_8.cs)] + + For more information, see [Implicitly typed local variables](../programming-guide/classes-and-structs/implicitly-typed-local-variables.md) and [Type relationships in LINQ query operations](../programming-guide/concepts/linq/type-relationships-in-linq-query-operations.md). + +### Starting a query expression + + A query expression must begin with a `from` clause. It specifies a data source together with a range variable. The range variable represents each successive element in the source sequence as the source sequence is being traversed. The range variable is strongly typed based on the type of elements in the data source. In the following example, because `countries` is an array of `Country` objects, the range variable is also typed as `Country`. Because the range variable is strongly typed, you can use the dot operator to access any available members of the type. + + [!code-cs[csrefQueryExpBasics#53](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_9.cs)] + + The range variable is in scope until the query is exited either with a semicolon or with a *continuation* clause. + + A query expression may contain multiple `from` clauses. Use additional `from` clauses when each element in the source sequence is itself a collection or contains a collection. For example, assume that you have a collection of `Country` objects, each of which contains a collection of `City` objects named `Cities`. To query the `City` objects in each `Country`, use two `from` clauses as shown here: + + [!code-cs[csrefQueryExpBasics#54](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_10.cs)] + + For more information, see [from clause](../language-reference/keywords/from-clause.md). + +### Ending a query expression + + A query expression must end with either a `group` clause or a `select` clause. + +#### group clause + + Use the `group` clause to produce a sequence of groups organized by a key that you specify. The key can be any data type. For example, the following query creates a sequence of groups that contains one or more `Country` objects and whose key is a `char` value. + + [!code-cs[csrefQueryExpBasics#55](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_11.cs)] + + For more information about grouping, see [group clause](../language-reference/keywords/group-clause.md). + +#### select clause + Use the `select` clause to produce all other types of sequences. A simple `select` clause just produces a sequence of the same type of objects as the objects that are contained in the data source. In this example, the data source contains `Country` objects. The `orderby` clause just sorts the elements into a new order and the `select` clause produces a sequence of the reordered `Country` objects. + + [!code-cs[csrefQueryExpBasics#56](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_12.cs)] + + The `select` clause can be used to transform source data into sequences of new types. This transformation is also named a *projection*. In the following example, the `select` clause *projects* a sequence of anonymous types which contains only a subset of the fields in the original element. Note that the new objects are initialized by using an object initializer. + + [!code-cs[csrefQueryExpBasics#57](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_13.cs)] + + For more information about all the ways that a `select` clause can be used to transform source data, see [select clause](../language-reference/keywords/select-clause.md). + +#### Continuations with "into" + + You can use the `into` keyword in a `select` or `group` clause to create a temporary identifier that stores a query. Do this when you must perform additional query operations on a query after a grouping or select operation. In the following example `countries` are grouped according to population in ranges of 10 million. After these groups are created, additional clauses filter out some groups, and then to sort the groups in ascending order. To perform those additional operations, the continuation represented by `countryGroup` is required. + + [!code-cs[csrefQueryExpBasics#58](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_14.cs)] + + For more information, see [into](../language-reference/keywords/into.md). + +### Filtering, ordering, and joining + + Between the starting `from` clause, and the ending `select` or `group` clause, all other clauses (`where`, `join`, `orderby`, `from`, `let`) are optional. Any of the optional clauses may be used zero times or multiple times in a query body. + +#### where clause + + Use the `where` clause to filter out elements from the source data based on one or more predicate expressions. The `where` clause in the following example has one predicate with two conditions. + + [!code-cs[csrefQueryExpBasics#59]../../../samples/snippets/csharp/concepts/linq/query-expression-basics_15.cs)] + + For more information, see [where clause](../language-reference/keywords/where-clause.md). + +#### orderby clause + + Use the `orderby` clause to sort the results in either ascending or descending order. You can also specify secondary sort orders. The following example performs a primary sort on the `country` objects by using the `Area` property. It then performs a secondary sort by using the `Population` property. + + [!code-cs[csrefQueryExpBasics#60](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_16.cs)] + + The `ascending` keyword is optional; it is the default sort order if no order is specified. For more information, see [orderby clause](../language-reference/keywords/orderby-clause.md). + +#### join clause + + Use the `join` clause to associate and/or combine elements from one data source with elements from another data source based on an equality comparison between specified keys in each element. In LINQ, join operations are performed on sequences of objects whose elements are different types. After you have joined two sequences, you must use a `select` or `group` statement to specify which element to store in the output sequence. You can also use an anonymous type to combine properties from each set of associated elements into a new type for the output sequence. The following example associates `prod` objects whose `Category` property matches one of the categories in the `categories` string array. Products whose `Category` does not match any string in `categories` are filtered out. The `select` statement projects a new type whose properties are taken from both `cat` and `prod`. + + [!code-cs[csrefQueryExpBasics#61](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_17.cs)] + + You can also perform a group join by storing the results of the `join` operation into a temporary variable by using the [into](../language-reference/keywords/into.md) keyword. For more information, see [join clause](../language-reference/keywords/join-clause.md). + +#### let clause + + Use the `let` clause to store the result of an expression, such as a method call, in a new range variable. In the following example, the range variable `firstName` stores the first element of the array of strings that is returned by `Split`. + + [!code-cs[csrefQueryExpBasics#62](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_18.cs)] + + For more information, see [let clause](../language-reference/keywords/let-clause.md). + +### Subqueries in a query expression + + A query clause may itself contain a query expression, which is sometimes referred to as a *subquery*. Each subquery starts with its own `from` clause that does not necessarily point to the same data source in the first `from` clause. For example, the following query shows a query expression that is used in the select statement to retrieve the results of a grouping operation. + + [!code-cs[csrefQueryExpBasics#63](../../../samples/snippets/csharp/concepts/linq/query-expression-basics_19.cs)] + + For more information, see [How to: perform a subquery on a grouping operation](perform-a-subquery-on-a-grouping-operation.md). + +## See Also + [C# programming guide](../programming-guide/index.md) + [LINQ query expressions](index.md) + [Query keywords (LINQ)](../language-reference/keywords/query-keywords.md) + [Standard query operators overview](../programming-guide/concepts/linq/standard-query-operators-overview.md) \ No newline at end of file diff --git a/docs/csharp/linq/return-a-query-from-a-method.md b/docs/csharp/linq/return-a-query-from-a-method.md new file mode 100644 index 0000000000000..016ee208bcd76 --- /dev/null +++ b/docs/csharp/linq/return-a-query-from-a-method.md @@ -0,0 +1,27 @@ +--- +title: "Return a query from a method" +description: How to return a query. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 11/30/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: db220f79-c35b-41f2-886c-cd068672d42d + +--- +# How to: Return a Query from a Method (C# Programming Guide) +This example shows how to return a query from a method as the return value and as an `out` parameter. + + Query objects are composable, meaning that you can return a query from a method. Objects that represent queries do not store the resulting collection, but rather the steps to produce the results when needed. The advantage of returning query objects from methods is that they can be further composed or modified. Therefore any return value or `out` parameter of a method that returns a query must also have that type. If a method materializes a query into a concrete or type, it is considered to be returning the query results instead of the query itself. A query variable that is returned from a method can still be composed or modified. + +## Example + In the following example, the first method returns a query as a return value, and the second method returns a query as an `out` parameter. Note that in both cases it is a query that is returned, not query results. + + [!code-cs[csProgGuideLINQ#80](../../../samples/snippets/csharp/concepts/linq/how-to-return-a-query-from-a-method_1.cs)] + +## See Also + [LINQ Query Expressions](index.md) \ No newline at end of file diff --git a/docs/csharp/linq/store-the-results-of-a-query-in-memory.md b/docs/csharp/linq/store-the-results-of-a-query-in-memory.md new file mode 100644 index 0000000000000..c4fffb36d9819 --- /dev/null +++ b/docs/csharp/linq/store-the-results-of-a-query-in-memory.md @@ -0,0 +1,34 @@ +--- +title: "Store the results of a query in memory" +description: How to store results. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 11/30/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: 5b863961-1750-4cf9-9607-acea5054d15a +--- +# Store the results of a query in memory + +A query is basically a set of instructions for how to retrieve and organize data. Queries are executed lazily, as each subsequent item in the result is requested. When you use `foreach` to iterate the results, items are returned as accessed. To evaluate a query and store its results without executing a `foreach` loop, just call one of the following methods on the query variable: + +- + +- + +- + +- + + We recommend that when you store the query results, you assign the returned collection object to a new variable as shown in the following example: + +## Example + [!code-cs[csProgGuideLINQ#25](../../../samples/snippets/csharp/concepts/linq/how-to-store-the-results-of-a-query-in-memory_1.cs)] + + +## See Also + [LINQ Query Expressions](index.md) \ No newline at end of file diff --git a/docs/csharp/linq/write-linq-queries.md b/docs/csharp/linq/write-linq-queries.md new file mode 100644 index 0000000000000..3c03e0d7834c1 --- /dev/null +++ b/docs/csharp/linq/write-linq-queries.md @@ -0,0 +1,92 @@ +--- +title: "Write LINQ queries in C#" +description: How to write queries. +keywords: .NET, .NET Core, C# +author: stevehoag +manager: wpickett +ms.author: wiwagn +ms.date: 12/1/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: 30703f79-cf3a-4d02-b892-c95d58a1d9ed +--- + +# Write LINQ queries in C# + +This topic shows the three ways in which you can write a LINQ query in C#: + +1. Use query syntax. + +2. Use method syntax. + +3. Use a combination of query syntax and method syntax. + + The following examples demonstrate some simple LINQ queries by using each approach listed previously. In general, the rule is to use (1) whenever possible, and use (2) and (3) whenever necessary. + +> [!NOTE] +> These queries operate on simple in-memory collections; however, the basic syntax is identical to that used in LINQ to Entities and LINQ to XML. + +## Example + +## Query syntax + The recommended way to write most queries is to use *query syntax* to create *query expressions*. The following example shows three query expressions. The first query expression demonstrates how to filter or restrict results by applying conditions with a `where` clause. It returns all elements in the source sequence whose values are greater than 7 or less than 3. The second expression demonstrates how to order the returned results. The third expression demonstrates how to group results according to a key. This query returns two groups based on the first letter of the word. + + [!code-cs[csProgGuideLINQ#5](../../../samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_1.cs)] + + Note that the type of the queries is . All of these queries could be written using `var` as shown in the following example: + + `var query = from num in numbers...` + + In each previous example, the queries do not actually execute until you iterate over the query variable in a `foreach` statement or other statement. For more information, see [Introduction to LINQ Queries](../programming-guide/concepts/linq/introduction-to-linq-queries.md). + +## Example + +## Method syntax + Some query operations must be expressed as a method call. The most common such methods are those that return singleton numeric values, such as , , , , and so on. These methods must always be called last in any query because they represent only a single value and cannot serve as the source for an additional query operation. The following example shows a method call in a query expression: + + [!code-cs[csProgGuideLINQ#6](../../../samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_2.cs)] + +## Example + If the method has Action or Func parameters, these are provided in the form of a [lambda](../programming-guide/statements-expressions-operators/lambda-expressions.md) expression, as shown in the following example: + + [!code-cs[csProgGuideLINQ#7](../../../samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_3.cs)] + + In the previous queries, only Query #4 executes immediately. This is because it returns a single value, and not a generic collection. The method itself has to use `foreach` in order to compute its value. + + Each of the previous queries can be written by using implicit typing with [var](../language-reference/keywords/var.md), as shown in the following example: + + [!code-cs[csProgGuideLINQ#8](../../../samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_4.cs)] + +## Example + +## Mixed query and method syntax + This example shows how to use method syntax on the results of a query clause. Just enclose the query expression in parentheses, and then apply the dot operator and call the method. In the following example, query #7 returns a count of the numbers whose value is between 3 and 7. In general, however, it is better to use a second variable to store the result of the method call. In this manner, the query is less likely to be confused with the results of the query. + + [!code-cs[csProgGuideLINQ#9](../../../samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_5.cs)] + + Because Query #7 returns a single value and not a collection, the query executes immediately. + + The previous query can be written by using implicit typing with `var`, as follows: + +```cs +var numCount = (from num in numbers... +``` + + It can be written in method syntax as follows: + +```cs +var numCount = numbers.Where(n => n < 3 || n > 7).Count(); +``` + + It can be written by using explicit typing, as follows: + +```cs +int numCount = numbers.Where(n => n < 3 || n > 7).Count(); +``` + +## See Also + [Walkthrough: Writing Queries in C#](../programming-guide/concepts/linq/walkthrough-writing-queries-linq.md) + [LINQ Query Expressions](index.md) + [where clause](../language-reference/keywords/where-clause.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/concepts/linq/index.md b/docs/csharp/programming-guide/concepts/linq/index.md index 6ff282bcba228..757b45ba8abdb 100644 --- a/docs/csharp/programming-guide/concepts/linq/index.md +++ b/docs/csharp/programming-guide/concepts/linq/index.md @@ -1,51 +1,3 @@ --- -title: "Language-Integrated Query (LINQ) (C#) | Microsoft Docs" -ms.custom: "" -ms.date: "2015-07-20" -ms.prod: .net -ms.reviewer: "" -ms.suite: "" -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -ms.assetid: 19dd1782-905b-4a9d-a3e9-618453037fa2 -caps.latest.revision: 4 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.mt: - - "cs-cz" - - "pl-pl" - - "pt-br" - - "tr-tr" +redirect_url: /dotnet/articles/csharp/linq/linq-in-csharp --- -# Language-Integrated Query (LINQ) (C#) -LINQ is a set of features that extends powerful query capabilities to the language syntax of C#. LINQ introduces standard, easily-learned patterns for querying and updating data, and the technology can be extended to support potentially any kind of data store. The .NET Framework includes LINQ provider assemblies that enable the use of LINQ with .NET Framework collections, SQL Server databases, ADO.NET Datasets, and XML documents. - -## In This Section - [Introduction to LINQ (C#)](../../../../csharp/programming-guide/concepts/linq/introduction-to-linq.md) - Provides a general introduction to the kinds of applications that you can write and the kinds of problems that you can solve with LINQ queries. - - [Getting Started with LINQ in C#](../../../../csharp/programming-guide/concepts/linq/getting-started-with-linq.md) - Describes the basic facts you should know in order to understand the C# documentation and samples. - - [Visual Studio IDE and Tools Support for LINQ (C#)](../../../../csharp/programming-guide/concepts/linq/visual-studio-ide-and-tools-support-for-linq.md) - Describes Visual Studio's Object Relational Designer, debugger support for queries, and other IDE features related to LINQ. - - [Standard Query Operators Overview (C#)](../../../../csharp/programming-guide/concepts/linq/standard-query-operators-overview.md) - Provides an introduction to the standard query operators. It also provides links to topics that have more information about each type of query operation. - - [LINQ to Objects (C#)](../../../../csharp/programming-guide/concepts/linq/linq-to-objects.md) - Includes links to topics that explain how to use LINQ to Objects to access in-memory data structures, - - [LINQ to XML (C#)](../../../../csharp/programming-guide/concepts/linq/linq-to-xml.md) - Includes links to topics that explain how to use LINQ to XML, which provides the in-memory document modification capabilities of the Document Object Model (DOM), and supports LINQ query expressions. - - [LINQ to ADO.NET (Portal Page)](../../../../csharp/programming-guide/concepts/linq/linq-to-adonet-portal-page.md) - Provides an entry point for documentation about LINQ to DataSet, LINQ to SQL, and LINQ to Entities. LINQ to DataSet enables you to build richer query capabilities into by using the same query functionality that is available for other data sources. LINQ to SQL provides a run-time infrastructure for managing relational data as objects. LINQ to Entities enables developers to write queries against the Entity Framework conceptual model by using C#. - - [Enabling a Data Source for LINQ Querying](../../../../csharp/programming-guide/concepts/linq/enabling-a-data-source-for-linq-querying1.md) - Provides an introduction to custom LINQ providers, LINQ expression trees, and other ways to extend LINQ. \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-create-a-nested-group.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-create-a-nested-group.md index 74101a533c08c..8cad51811d7f0 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-create-a-nested-group.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-create-a-nested-group.md @@ -1,55 +1,3 @@ --- -title: "How to: Create a Nested Group (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "queries [LINQ in C#], nested groups" - - "grouping groups in LINQ queries" - - "grouping LINQ queries" - - "groups [LINQ in C#], nested" - - "nested queries [C#]" - - "query expressions [LINQ in C#], nested groups" -ms.assetid: f48c64af-6d4e-473c-ab27-02f78b5ec2b9 -caps.latest.revision: 12 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/create-a-nested-group --- -# How to: Create a Nested Group (C# Programming Guide) -The following example shows how to create nested groups in a [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)] query expression. Each group that is created according to student year or grade level is then further subdivided into groups based on the individuals' names. - -## Example - [!code-cs[csProgGuideLINQ#24](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-create-a-nested-group_1.cs)] - - Note that three nested `foreach` loops are required to iterate over the inner elements of a nested group. - -## Compiling the Code - This example contains references to objects that are defined in the sample application in [How to: Query a Collection of Objects](../../../csharp/programming-guide/linq-query-expressions/how-to-query-a-collection-of-objects.md). To compile and run this method, paste it into the `StudentClass` class in that application and add a call to it from the `Main` method. - - When you adapt this method to your own application, remember that LINQ requires version 3.5 of the [!INCLUDE[dnprdnshort](../../../csharp/getting-started/includes/dnprdnshort_md.md)], and the project must contain a reference to System.Core.dll and a using directive for System.Linq. LINQ to SQL, LINQ to XML and LINQ to DataSet types require additional usings and references. - -## See Also - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-dynamically-specify-predicate-filters-at-runtime.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-dynamically-specify-predicate-filters-at-runtime.md index f63ba5781c096..6ea5d0f370b95 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-dynamically-specify-predicate-filters-at-runtime.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-dynamically-specify-predicate-filters-at-runtime.md @@ -1,108 +1,3 @@ --- -title: "How to: Dynamically Specify Predicate Filters at Runtime (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "queries [LINQ in C#], predicate filters" - - "dynamic queries [LINQ in C#]" - - "predicate filters [C#]" - - "predicates [C#]" - - "query expressions [LINQ in C#], predicate filters" -ms.assetid: 52f2dc7a-8353-4c6e-98d3-eec99a907a5f -caps.latest.revision: 22 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/dynamically-specify-predicate-filters-at-runtime --- -# How to: Dynamically Specify Predicate Filters at Runtime (C# Programming Guide) -In some cases you do not know until run time how many predicates you have to apply to source elements in the `where` clause. One way to dynamically specify multiple predicate filters is to use the method, as shown in the following example. The example is constructed in two ways. First, the project is run by filtering on values that are provided in the program. Then the project is run again by using input provided at run time. - -## To filter by using the Contains method - -1. Open a new console application in Visual Studio. Name it `PredicateFilters`. - -2. Copy the `StudentClass` class from [How to: Query a Collection of Objects](../../../csharp/programming-guide/linq-query-expressions/how-to-query-a-collection-of-objects.md) and paste it into namespace `PredicateFilters` underneath class `Program`. `StudentClass` provides a list of `Student` objects. - -3. Comment out the `Main` method in `StudentClass`. - -4. Replace class `Program` with the following code. - - [!code-cs[csProgGuideLINQ#26](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-dynamically-specify-predicate-filters-at-runtime_1.cs)] - -5. Add the following line to the `Main` method in class `DynamicPredicates`, under the declaration of `ids`. - -0 -6. Press F5 to run the project. - -7. The following output is displayed in a Command Prompt window: - - Garcia: 114 - - O'Donnell: 112 - - Omelchenko: 111 - -8. The next step is to run the project again, this time by using input entered at run time instead of array `ids`. In **Solution Explorer**, right-click **PredicateFilters** and then click **Properties**. - -9. Click the **Debug** tab. - -10. In the **Command line arguments** window, type 122, 117, 120, and 115, separated by spaces: `122 117 120 115`. When the project is run, those values become elements of `args`, the parameter of the `Main` method. - -11. Change `QueryByID(ids)` to `QueryByID(args)` in the `Main` method. - -12. Press F5 to run the project. - -13. The following output is displayed in a Command Prompt window: - - Adams: 120 - - Feng: 117 - - Garcia: 115 - - Tucker: 122 - -## To filter by using a switch statement - -1. You can use a `switch` statement to select among predetermined alternative queries. In the following example, `studentQuery` uses a different `where` clause depending on which grade level, or year, is specified at run time. - -2. Copy the following method and paste it into class `DynamicPredicates`. - - [!code-cs[csProgGuideLINQ#27](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-dynamically-specify-predicate-filters-at-runtime_2.cs)] - -3. In the **Command line arguments** window, replace the ID numbers from the previous procedure with an integer value between 1 and 4. - -4. In the `Main` method, replace the call to `QueryByID` with the following call, which sends the first element from the `args` array as its argument: `QueryByYear(args[0])`. - -5. Press F5 to run the project. - -## To use this method in your own applications - -- When you adapt this method to your own application, remember that LINQ requires version 3.5 or 4 of the [!INCLUDE[dnprdnshort](../../../csharp/getting-started/includes/dnprdnshort_md.md)], and that the project must contain a reference to System.Core.dll and a `using` directive for `System.Linq`. LINQ to SQL, LINQ to XML, and LINQ to DataSet types require additional `using` directives and references. - -## See Also - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) - [where clause](../../../csharp/language-reference/keywords/where-clause.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-group-query-results.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-group-query-results.md index b94922c130ff6..9ac308993bb91 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-group-query-results.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-group-query-results.md @@ -1,109 +1,3 @@ --- -title: "How to: Group Query Results (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "group clause examples [LINQ in C#]" - - "groups [LINQ in C#]" - - "queries [LINQ in C#], grouping" - - "query expressions [LINQ in C#], grouping" -ms.assetid: ee981053-3392-4245-a8c2-b3730211da0d -caps.latest.revision: 19 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/group-query-results --- -# How to: Group Query Results (C# Programming Guide) -Grouping is one of the most powerful capabilities of [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)]. The following examples show how to group data in various ways: - -- By a single property. - -- By the first letter of a string property. - -- By a computed numeric range. - -- By Boolean predicate or other expression. - -- By a compound key. - - In addition, the last two queries project their results into a new anonymous type that contains only the student's first and last name. For more information, see the [group clause](../../../csharp/language-reference/keywords/group-clause.md). - -## Example - All the examples in this topic use the following helper classes and data sources. - - [!code-cs[csProgGuideLINQ#15](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-group-query-results_1.cs)] - -## Example - The following example shows how to group source elements by using a single property of the element as the group key. In this case the key is a `string`, the student's last name. It is also possible to use a substring for the key. The grouping operation uses the default equality comparer for the type. - - Paste the following method into the `StudentClass` class. Change the calling statement in the `Main` method to `sc.GroupBySingleProperty()`. - - [!code-cs[csProgGuideLINQ#17](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-group-query-results_2.cs)] - -## Example - The following example shows how to group source elements by using something other than a property of the object for the group key. In this example, the key is the first letter of the student's last name. - - Paste the following method into the `StudentClass` class. Change the calling statement in the `Main` method to `sc.GroupBySubstring()`. - - [!code-cs[csProgGuideLINQ#18](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-group-query-results_3.cs)] - -## Example - The following example shows how to group source elements by using a numeric range as a group key. The query then projects the results into an anonymous type that contains only the first and last name and the percentile range to which the student belongs. An anonymous type is used because it is not necessary to use the complete `Student` object to display the results. `GetPercentile` is a helper function that calculates a percentile based on the student's average score. The method returns an integer between 0 and 10. - - [!code-cs[csProgGuideLINQ#50](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-group-query-results_4.cs)] - - Paste the following method into the `StudentClass` class. Change the calling statement in the `Main` method to `sc.GroupByRange()`. - - [!code-cs[csProgGuideLINQ#19](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-group-query-results_5.cs)] - -## Example - The following example shows how to group source elements by using a Boolean comparison expression. In this example, the Boolean expression tests whether a student's average exam score is greater than 75. As in previous examples, the results are projected into an anonymous type because the complete source element is not needed. Note that the properties in the anonymous type become properties on the `Key` member and can be accessed by name when the query is executed. - - Paste the following method into the `StudentClass` class. Change the calling statement in the `Main` method to `sc.GroupByBoolean()`. - - [!code-cs[csProgGuideLINQ#20](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-group-query-results_6.cs)] - -## Example - The following example shows how to use an anonymous type to encapsulate a key that contains multiple values. In this example, the first key value is the first letter of the student's last name. The second key value is a Boolean that specifies whether the student scored over 85 on the first exam. You can order the groups by any property in the key. - - Paste the following method into the `StudentClass` class. Change the calling statement in the `Main` method to `sc.GroupByCompositeKey()`. - - [!code-cs[csProgGuideLINQ#21](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-group-query-results_7.cs)] - -## Compiling the Code - Copy and paste each method that you want to test into the `StudentClass` class. Add a calling statement for the method to the `Main` method and press F5. - - When you adapt these methods to your own application, remember that LINQ requires version 3.5 or 4 of the [!INCLUDE[dnprdnshort](../../../csharp/getting-started/includes/dnprdnshort_md.md)], and that the project must contain a reference to System.Core.dll and a using directive for System.Linq. LINQ to SQL, LINQ to XML, and LINQ to DataSet types require additional using directives and references. - -## See Also - - - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) - [group clause](../../../csharp/language-reference/keywords/group-clause.md) - [Anonymous Types](../../../csharp/programming-guide/classes-and-structs/anonymous-types.md) - [How to: Perform a Subquery on a Grouping Operation](../../../csharp/programming-guide/linq-query-expressions/how-to-perform-a-subquery-on-a-grouping-operation.md) - [How to: Create a Nested Group](../../../csharp/programming-guide/linq-query-expressions/how-to-create-a-nested-group.md) - [Grouping Data](http://msdn.microsoft.com/library/43892bd5-1634-479c-8249-bb7525d87c5d) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-group-results-by-contiguous-keys.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-group-results-by-contiguous-keys.md index 314cb4dd4ef73..c16825180330d 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-group-results-by-contiguous-keys.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-group-results-by-contiguous-keys.md @@ -1,75 +1,3 @@ --- -title: "How to: Group Results by Contiguous Keys (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "contiguous keys [LINQ in C#]" -ms.assetid: 0f0f48a8-e13b-4274-8903-3b73f68cd18e -caps.latest.revision: 11 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/group-results-by-contiguous-keys --- -# How to: Group Results by Contiguous Keys (C# Programming Guide) -The following example shows how to group elements into chunks that represent subsequences of contiguous keys. For example, assume that you are given the following sequence of key-value pairs: - -|Key|Value| -|---------|-----------| -|A|We| -|A|think| -|A|that| -|B|Linq| -|C|is| -|A|really| -|B|cool| -|B|!| - - The following groups will be created in this order: - -1. We, think, that - -2. Linq - -3. is - -4. really - -5. cool, ! - - The solution is implemented as an extension method that is thread-safe and that returns its results in a streaming manner. In other words, it produces its groups as it moves through the source sequence. Unlike the `group` or `orderby` operators, it can begin returning groups to the caller before all of the sequence has been read. - - Thread-safety is accomplished by making a copy of each group or chunk as the source sequence is iterated, as explained in the source code comments. If the source sequence has a large sequence of contiguous items, the common language runtime may throw an . - -## Example - The following example shows both the extension method and the client code that uses it. - - [!code-cs[cscsrefContiguousGroups#1](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/how-to-group-results-by-contiguous-keys_1.cs)] - - To use the extension method in your project, copy the `MyExtensions` static class to a new or existing source code file and if it is required, add a `using` directive for the namespace where it is located. - -## See Also - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) - [Classification of Standard Query Operators by Manner of Execution](http://msdn.microsoft.com/library/67bf1ae5-e632-44a8-a5d6-3b78b6d0e73e) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-handle-exceptions-in-query-expressions.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-handle-exceptions-in-query-expressions.md index 5d3e9ae616999..69602d15b417f 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-handle-exceptions-in-query-expressions.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-handle-exceptions-in-query-expressions.md @@ -1,66 +1,3 @@ --- -title: "How to: Handle Exceptions in Query Expressions (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "exceptions [C#], LINQ queries" - - "query expressions [LINQ in C#], exceptions" - - "queries [LINQ in C#], exceptions" -ms.assetid: 4ce6c081-7731-4b8f-b4fa-d947f165a18a -caps.latest.revision: 15 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/handle-exceptions-in-query-expressions --- -# How to: Handle Exceptions in Query Expressions (C# Programming Guide) -It is possible to call any method in the context of a query expression. However, we recommend that you avoid calling any method in a query expression that can create a side effect such as modifying the contents of the data source or throwing an exception. This example shows how to avoid raising exceptions when you call methods in a query expression without violating the general [!INCLUDE[dnprdnshort](../../../csharp/getting-started/includes/dnprdnshort_md.md)] guidelines on exception handling. Those guidelines state that it is acceptable to catch a specific exception when you understand why it will be thrown in a given context. For more information, see [Best Practices for Exceptions](http://msdn.microsoft.com/library/f06da765-235b-427a-bfb6-47cd219af539). - - The final example shows how to handle those cases when you must throw an exception during execution of a query. - -## Example - The following example shows how to move exception handling code outside a query expression. This is only possible when the method does not depend on any variables local to the query. - - [!code-cs[csProgGuideLINQ#10](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-handle-exceptions-in-query-expressions_1.cs)] - -## Example - In some cases, the best response to an exception that is thrown from within a query might be to stop the query execution immediately. The following example shows how to handle exceptions that might be thrown from inside a query body. Assume that `SomeMethodThatMightThrow` can potentially cause an exception that requires the query execution to stop. - - Note that the `try` block encloses the `foreach` loop, and not the query itself. This is because the `foreach` loop is the point at which the query is actually executed. For more information, see [Introduction to LINQ Queries (C#)](../../../csharp/programming-guide/concepts/linq/introduction-to-linq-queries.md). - - [!code-cs[csProgGuideLINQ#12](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-handle-exceptions-in-query-expressions_2.cs)] - -## Compiling the Code - -- Create a [!INCLUDE[vs_current_short](../../../csharp/programming-guide/classes-and-structs/includes/vs_current_short_md.md)] project that targets the .NET Framework version 3.5. By default, the project has a reference to System.Core.dll and a `using` directive for the System.Linq namespace. - -- Copy the code into your project. - -- Press F5 to compile and run the program. - - Press any key to exit the console window. - -## See Also - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-handle-null-values-in-query-expressions.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-handle-null-values-in-query-expressions.md index 1b8f68b77c375..1148fad6107b9 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-handle-null-values-in-query-expressions.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-handle-null-values-in-query-expressions.md @@ -1,56 +1,3 @@ --- -title: "How to: Handle Null Values in Query Expressions (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "query expressions [LINQ in C#], null values" - - "null values [LINQ in C#]" - - "queries [LINQ in C#], null values" -ms.assetid: cb34f7a1-7ef5-466a-90ba-91da30ab525d -caps.latest.revision: 6 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/handle-null-values-in-query-expressions --- -# How to: Handle Null Values in Query Expressions (C# Programming Guide) -This example shows how to handle possible null values in source collections. An object collection such as an can contain elements whose value is [null](../../../csharp/language-reference/keywords/null.md). If a source collection is null or contains an element whose value is null, and your query does not handle null values, a will be thrown when you execute the query. - -## Example - You can code defensively to avoid a null reference exception as shown in the following example: - - [!code-cs[csProgGuideLINQ#82](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-handle-null-values-in-query-expressions_1.cs)] - - In the previous example, the `where` clause filters out all null elements in the categories sequence. This technique is independent of the null check in the join clause. The conditional expression with null in this example works because `Products.CategoryID` is of type `int?` which is shorthand for `Nullable`. - -## Example - In a join clause, if only one of the comparison keys is a nullable value type, you can cast the other to a nullable type in the query expression. In the following example, assume that `EmployeeID` is a column that contains values of type `int?`: - - [!code-cs[csProgGuideLINQ#83](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-handle-null-values-in-query-expressions_2.cs)] - -## See Also - - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) - [Nullable Types](../../../csharp/programming-guide/nullable-types/index.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-join-by-using-composite-keys.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-join-by-using-composite-keys.md index 9ee26f4ce67dd..5467c06259e1d 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-join-by-using-composite-keys.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-join-by-using-composite-keys.md @@ -1,79 +1,3 @@ --- -title: "How to: Join by Using Composite Keys (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "composite keys [LINQ in C#]" - - "joins [C#]" - - "query expressions [LINQ in C#], joins" - - "joins [C#], composite keys" - - "queries [LINQ in C#], joins" -ms.assetid: 3e015b3f-9cca-4b0c-aa97-dca0d36ea592 -caps.latest.revision: 8 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/join-by-using-composite-keys --- -# How to: Join by Using Composite Keys (C# Programming Guide) -This example shows how to perform join operations in which you want to use more than one key to define a match. This is accomplished by using a composite key. You create a composite key as an anonymous type or named typed with the values that you want to compare. If the query variable will be passed across method boundaries, use a named type that overrides and for the key. The names of the properties, and the order in which they occur, must be identical in each key. - -## Example - The following example demonstrates how to use a composite key to join data from three tables: - -``` -var query = from o in db.Orders - from p in db.Products - join d in db.OrderDetails - on new {o.OrderID, p.ProductID} equals new {d.OrderID, d.ProductID} into details - from d in details - select new {o.OrderID, p.ProductID, d.UnitPrice}; -``` - - Type inference on composite keys depends on the names of the properties in the keys, and the order in which they occur. If the properties in the source sequences do not have the same names, you must assign new names in the keys. For example, if the `Orders` table and `OrderDetails` table each used different names for their columns, you could create composite keys by assigning identical names in the anonymous types: - -``` -join...on new {Name = o.CustomerName, ID = o.CustID} equals - new {Name = d.CustName, ID = d.CustID } -``` - - Composite keys can be also used in a `group` clause. - -## Compiling the Code - -- To compile and run this code, follow these steps: - -- Open [How to: Connect to the Northwind Database](http://msdn.microsoft.com/library/cc6cb79f-d035-41f8-b398-8d4a45922bfb) and follow the instructions to set up the project and create the database connection. For more information, see [How to: Install Sample Databases](http://msdn.microsoft.com/library/ed1291f6-604c-4972-ae22-0345c6dea12e). - -- In samples.cs, create a new empty method that takes a Northwind input parameter named db (similar to the other methods in that file). Paste the code from this example into the method body. - -- Modify program.cs to call the new method from `Main`. - -- Press F5 to compile and run the query. - -## See Also - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) - [join clause](../../../csharp/language-reference/keywords/join-clause.md) - [group clause](../../../csharp/language-reference/keywords/group-clause.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-order-the-results-of-a-join-clause.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-order-the-results-of-a-join-clause.md index 92afefa71aa9b..efe70450ceaab 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-order-the-results-of-a-join-clause.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-order-the-results-of-a-join-clause.md @@ -1,61 +1,3 @@ --- -title: "How to: Order the Results of a Join Clause (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "join clause [C#]" - - "joins [C#], ordering results" - - "query expressions [LINQ in C#], joins" - - "queries [LINQ in C#], joins" -ms.assetid: 83f36f16-2ba3-453f-8b9f-7d02b415610e -caps.latest.revision: 6 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/order-the-results-of-a-join-clause --- -# How to: Order the Results of a Join Clause (C# Programming Guide) -This example shows how to order the results of a join operation. Note that the ordering is performed after the join. Although you can use an `orderby` clause with one or more of the source sequences before the join, generally we do not recommend it. Some [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)] providers might not preserve that ordering after the join. - -## Example - This query creates a group join, and then sorts the groups based on the category element, which is still in scope. Inside the anonymous type initializer, a sub-query orders all the matching elements from the products sequence. - - [!code-cs[csProgGuideLINQ#81](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-order-the-results-of-a-join-clause_1.cs)] - -## Compiling the Code - -- Create a [!INCLUDE[vs_current_short](../../../csharp/programming-guide/classes-and-structs/includes/vs_current_short_md.md)] project that targets the .NET Framework version 3.5. By default, the project has a reference to System.Core.dll and a `using` directive for the System.Linq namespace. - -- Copy the code into your project. - -- Press F5 to compile and run the program. - -- Press any key to exit the console window. - -## See Also - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) - [orderby clause](../../../csharp/language-reference/keywords/orderby-clause.md) - [join clause](../../../csharp/language-reference/keywords/join-clause.md) - [Join Operations](http://msdn.microsoft.com/library/442d176d-028c-4beb-8d22-407d4ef89107) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-a-subquery-on-a-grouping-operation.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-a-subquery-on-a-grouping-operation.md index 87d88ff41e88a..7782037b9376a 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-a-subquery-on-a-grouping-operation.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-a-subquery-on-a-grouping-operation.md @@ -1,59 +1,3 @@ --- -title: "How to: Perform a Subquery on a Grouping Operation (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "queries [LINQ in C#], subqueires" - - "query expressions [LINQ in C#], subqueries" - - "groups [C#], LINQ query expressions" - - "subqueries [C#]" - - "queries [LINQ in C#], grouping" - - "grouping LINQ queries [C#]" - - "query expressions [LINQ in C#], grouping" - - "groups [LINQ in C#], subqueries" -ms.assetid: 7b0805cd-53b4-429d-86b6-d37fb08f2c95 -caps.latest.revision: 15 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/perform-a-subquery-on-a-grouping-operation --- -# How to: Perform a Subquery on a Grouping Operation (C# Programming Guide) -This topic shows two different ways to create a query that orders the source data into groups, and then performs a subquery over each group individually. The basic technique in each example is to group the source elements by using a *continuation* named `newGroup`, and then generating a new subquery against `newGroup`. This subquery is run against each new group that is created by the outer query. Note that in this particular example the final output is not a group, but a flat sequence of anonymous types. - - For more information about how to group, see [group clause](../../../csharp/language-reference/keywords/group-clause.md). - - For more information about continuations, see [into](../../../csharp/language-reference/keywords/into.md). The following example uses an in-memory data structure as the data source, but the same principles apply for any kind of [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)] data source. - -## Example - [!code-cs[csProgGuideLINQ#23](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-perform-a-subquery-on-a-grouping-operation_1.cs)] - -## Compiling the Code - This example contains references to objects that are defined in the sample application in [How to: Query a Collection of Objects](../../../csharp/programming-guide/linq-query-expressions/how-to-query-a-collection-of-objects.md). To compile and run this method, paste it into the `StudentClass` class in that application and add a call to it from the `Main` method. - - When you adapt this method to your own application, remember that LINQ requires version 3.5 of the [!INCLUDE[dnprdnshort](../../../csharp/getting-started/includes/dnprdnshort_md.md)], and the project must contain a reference to System.Core.dll and a using directive for System.Linq. LINQ to SQL, LINQ to XML and LINQ to DataSet types require additional usings and references. - -## See Also - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-custom-join-operations.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-custom-join-operations.md index 3bd88877fda52..f25cfc5e8a0a5 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-custom-join-operations.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-custom-join-operations.md @@ -1,83 +1,3 @@ --- -title: "How to: Perform Custom Join Operations (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "custom joins [C#]" - - "joins [C#], custom" - - "query expressions [LINQ in C#], joins" - - "queries [LINQ in C#], joins" -ms.assetid: a05e2ab1-410d-4a1d-8ada-af93539682c9 -caps.latest.revision: 13 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/perform-custom-join-operations --- -# How to: Perform Custom Join Operations (C# Programming Guide) -This example shows how to perform join operations that are not possible with the `join` clause. In a query expression, the `join` clause is limited to, and optimized for, equijoins, which are by far the most common type of join operation. When performing an equijoin, you will probably always get the best performance by using the `join` clause. - - However, the `join` clause cannot be used in the following cases: - -- When the join is predicated on an expression of inequality (a non-equijoin). - -- When the join is predicated on more than one expression of equality or inequality. - -- When you have to introduce a temporary range variable for the right side (inner) sequence before the join operation. - - To perform joins that are not equijoins, you can use multiple `from` clauses to introduce each data source independently. You then apply a predicate expression in a `where` clause to the range variable for each source. The expression also can take the form of a method call. - -> [!NOTE] -> Do not confuse this kind of custom join operation with the use of multiple `from` clauses to access inner collections. For more information, see [join clause](../../../csharp/language-reference/keywords/join-clause.md). - -## Example - The first method in the following example shows a simple cross join. Cross joins must be used with caution because they can produce very large result sets. However, they can be useful in some scenarios for creating source sequences against which additional queries are run. - - The second method produces a sequence of all the products whose category ID is listed in the category list on the left side. Note the use of the `let` clause and the `Contains` method to create a temporary array. It also is possible to create the array before the query and eliminate the first `from` clause. - - [!code-cs[csProgGuideLINQ#64](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-perform-custom-join-operations_1.cs)] - -## Example - In the following example, the query must join two sequences based on matching keys that, in the case of the inner (right side) sequence, cannot be obtained prior to the join clause itself. If this join were performed with a `join` clause, then the `Split` method would have to be called for each element. The use of multiple `from` clauses enables the query to avoid the overhead of the repeated method call. However, since `join` is optimized, in this particular case it might still be faster than using multiple `from` clauses. The results will vary depending primarily on how expensive the method call is. - - [!code-cs[csProgGuideLINQ#13](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-perform-custom-join-operations_2.cs)] - -## Compiling the Code - -- Create a [!INCLUDE[vs_current_short](../../../csharp/programming-guide/classes-and-structs/includes/vs_current_short_md.md)] console application project that targets [!INCLUDE[dnprdnshort](../../../csharp/getting-started/includes/dnprdnshort_md.md)] 3.5 or later. By default, the project has a reference to System.Core.dll and a `using` directive for the System.Linq namespace. - -- Replace the `Program` class with the code in the previous example. - -- Follow the instructions in [How to: Join Content from Dissimilar Files (LINQ)](http://msdn.microsoft.com/library/9ce5ce84-b38f-4e48-bf15-382e7a488f0b) to set up the data files, scores.csv and names.csv. - -- Press F5 to compile and run the program. - -- Press any key to exit the console window. - -## See Also - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) - [join clause](../../../csharp/language-reference/keywords/join-clause.md) - [Join Operations](http://msdn.microsoft.com/library/442d176d-028c-4beb-8d22-407d4ef89107) - [How to: Order the Results of a Join Clause](../../../csharp/programming-guide/linq-query-expressions/how-to-order-the-results-of-a-join-clause.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-grouped-joins.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-grouped-joins.md index 12226f7630c20..645c9df0366d8 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-grouped-joins.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-grouped-joins.md @@ -1,83 +1,3 @@ --- -title: "How to: Perform Grouped Joins (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "group joins [LINQ in C#]" - - "joins [C#], group" - - "query expressions [LINQ in C#], joins" - - "queries [LINQ in C#], joins" -ms.assetid: 31b654c0-77ac-43fa-be11-aa38e14cae2d -caps.latest.revision: 23 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/perform-grouped-joins --- -# How to: Perform Grouped Joins (C# Programming Guide) -The group join is useful for producing hierarchical data structures. It pairs each element from the first collection with a set of correlated elements from the second collection. - - For example, a class or a relational database table named Student might contain two fields: Id and Name. A second class or relational database table named Course might contain two fields: StudentId and CourseTitle. A group join of these two data sources, based on matching Student.Id and Course.StudentId, would group each Student with a collection of Course objects (which might be empty). - -> [!NOTE] -> Each element of the first collection appears in the result set of a group join regardless of whether correlated elements are found in the second collection. In the case where no correlated elements are found, the sequence of correlated elements for that element is empty. The result selector therefore has access to every element of the first collection. This differs from the result selector in a non-group join, which cannot access elements from the first collection that have no match in the second collection. - - The first example in this topic shows you how to perform a group join. The second example shows you how to use a group join to create XML elements. - -## Example - -### Group Join Example - The following example performs a group join of objects of type `Person` and `Pet` based on the `Person` matching the `Pet.Owner` property. Unlike a non-group join, which would produce a pair of elements for each match, the group join produces only one resulting object for each element of the first collection, which in this example is a `Person` object. The corresponding elements from the second collection, which in this example are `Pet` objects, are grouped into a collection. Finally, the result selector function creates an anonymous type for each match that consists of `Person.FirstName` and a collection of `Pet` objects. - - [!code-cs[CsLINQProgJoining#5](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/how-to-perform-grouped-joins_1.cs)] - -## Example - -### Group Join to Create XML Example - Group joins are ideal for creating XML by using [!INCLUDE[sqltecxlinq](../../../csharp/programming-guide/concepts/linq/includes/sqltecxlinq_md.md)]. The following example is similar to the previous example except that instead of creating anonymous types, the result selector function creates XML elements that represent the joined objects. For more information about [!INCLUDE[sqltecxlinq](../../../csharp/programming-guide/concepts/linq/includes/sqltecxlinq_md.md)], see [LINQ to XML](http://msdn.microsoft.com/library/f0fe21e9-ee43-4a55-b91a-0800e5782c13). - - [!code-cs[CsLINQProgJoining#6](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/how-to-perform-grouped-joins_2.cs)] - -## Compiling the Code - -- Create a new **Console Application** project in [!INCLUDE[vs_current_short](../../../csharp/programming-guide/classes-and-structs/includes/vs_current_short_md.md)]. - -- Add a reference to System.Core.dll and to System.Xml.Linq.dll if they are not already referenced. - -- Include the and namespaces. - -- Copy and paste the code from the example into the program.cs file, below the `Main` method. Add a line of code to the `Main` method to call the method you pasted in. - -- Run the program. - -## See Also - - - [Join Operations](http://msdn.microsoft.com/library/442d176d-028c-4beb-8d22-407d4ef89107) - [How to: Perform Inner Joins](../../../csharp/programming-guide/linq-query-expressions/how-to-perform-inner-joins.md) - [How to: Perform Left Outer Joins](../../../csharp/programming-guide/linq-query-expressions/how-to-perform-left-outer-joins.md) - [LINQ to XML](http://msdn.microsoft.com/library/f0fe21e9-ee43-4a55-b91a-0800e5782c13) - [Anonymous Types](../../../csharp/programming-guide/classes-and-structs/anonymous-types.md) - [Anonymous Types](../../../visual-basic/programming-guide/language-features/objects-and-classes/anonymous-types.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-inner-joins.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-inner-joins.md index 51b98511194ac..8cb175a81c335 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-inner-joins.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-inner-joins.md @@ -1,116 +1,3 @@ --- -title: "How to: Perform Inner Joins (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "joins [C#], inner" - - "inner joins [LINQ in C#]" - - "query expressions [LINQ in C#], joins" - - "queries [LINQ in C#], joins" -ms.assetid: d9edb404-8314-413e-ae51-83bb86c7a4b5 -caps.latest.revision: 25 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/perform-inner-joins --- -# How to: Perform Inner Joins (C# Programming Guide) -In relational database terms, an *inner join* produces a result set in which each element of the first collection appears one time for every matching element in the second collection. If an element in the first collection has no matching elements, it does not appear in the result set. The method, which is called by the `join` clause in C#, implements an inner join. - - This topic shows you how to perform four variations of an inner join: - -- A simple inner join that correlates elements from two data sources based on a simple key. - -- An inner join that correlates elements from two data sources based on a *composite* key. A composite key, which is a key that consists of more than one value, enables you to correlate elements based on more than one property. - -- A *multiple join* in which successive join operations are appended to each other. - -- An inner join that is implemented by using a group join. - -## Example - -## Simple Key Join Example - The following example creates two collections that contain objects of two user-defined types, `Person` and `Pet`. The query uses the `join` clause in C# to match `Person` objects with `Pet` objects whose `Owner` is that `Person`. The `select` clause in C# defines how the resulting objects will look. In this example the resulting objects are anonymous types that consist of the owner's first name and the pet's name. - - [!code-cs[CsLINQProgJoining#1](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/how-to-perform-inner-joins_1.cs)] - - Note that the `Person` object whose `LastName` is "Huff" does not appear in the result set because there is no `Pet` object that has `Pet.Owner` equal to that `Person`. - -## Example - -## Composite Key Join Example - Instead of correlating elements based on just one property, you can use a composite key to compare elements based on multiple properties. To do this, specify the key selector function for each collection to return an anonymous type that consists of the properties you want to compare. If you label the properties, they must have the same label in each key's anonymous type. The properties must also appear in the same order. - - The following example uses a list of `Employee` objects and a list of `Student` objects to determine which employees are also students. Both of these types have a `FirstName` and a `LastName` property of type . The functions that create the join keys from each list's elements return an anonymous type that consists of the `FirstName` and `LastName` properties of each element. The join operation compares these composite keys for equality and returns pairs of objects from each list where both the first name and the last name match. - - [!code-cs[CsLINQProgJoining#2](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/how-to-perform-inner-joins_2.cs)] - -## Example - -## Multiple Join Example - Any number of join operations can be appended to each other to perform a multiple join. Each `join` clause in C# correlates a specified data source with the results of the previous join. - - The following example creates three collections: a list of `Person` objects, a list of `Cat` objects, and a list of `Dog` objects. - - The first `join` clause in C# matches people and cats based on a `Person` object matching `Cat.Owner`. It returns a sequence of anonymous types that contain the `Person` object and `Cat.Name`. - - The second `join` clause in C# correlates the anonymous types returned by the first join with `Dog` objects in the supplied list of dogs, based on a composite key that consists of the `Owner` property of type `Person`, and the first letter of the animal's name. It returns a sequence of anonymous types that contain the `Cat.Name` and `Dog.Name` properties from each matching pair. Because this is an inner join, only those objects from the first data source that have a match in the second data source are returned. - - [!code-cs[CsLINQProgJoining#3](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/how-to-perform-inner-joins_3.cs)] - -## Example - -## Inner Join by using Grouped Join Example - The following example shows you how to implement an inner join by using a group join. - - In `query1`, the list of `Person` objects is group-joined to the list of `Pet` objects based on the `Person` matching the `Pet.Owner` property. The group join creates a collection of intermediate groups, where each group consists of a `Person` object and a sequence of matching `Pet` objects. - - By adding a second `from` clause to the query, this sequence of sequences is combined (or flattened) into one longer sequence. The type of the elements of the final sequence is specified by the `select` clause. In this example, that type is an anonymous type that consists of the `Person.FirstName` and `Pet.Name` properties for each matching pair. - - The result of `query1` is equivalent to the result set that would have been obtained by using the `join` clause without the `into` clause to perform an inner join. The `query2` variable demonstrates this equivalent query. - - [!code-cs[CsLINQProgJoining#4](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/how-to-perform-inner-joins_4.cs)] - -## Compiling the Code - -- Create a new Console Application project in [!INCLUDE[vs_current_short](../../../csharp/programming-guide/classes-and-structs/includes/vs_current_short_md.md)]. - -- Add a reference to System.Core.dll if it is not already referenced. - -- Include the namespace. - -- Copy and paste the code from the example into the program.cs file, below the `Main` method. Add a line of code to the `Main` method to call the method you pasted in. - -- Run the program. - -## See Also - - - [Join Operations](http://msdn.microsoft.com/library/442d176d-028c-4beb-8d22-407d4ef89107) - [How to: Perform Grouped Joins](../../../csharp/programming-guide/linq-query-expressions/how-to-perform-grouped-joins.md) - [How to: Perform Left Outer Joins](../../../csharp/programming-guide/linq-query-expressions/how-to-perform-left-outer-joins.md) - [How to: Join Two Collections](http://msdn.microsoft.com/library/c006ea6a-a93c-4cf7-9e79-0fc4fc397288) - [Anonymous Types](../../../csharp/programming-guide/classes-and-structs/anonymous-types.md) - [Anonymous Types](../../../visual-basic/programming-guide/language-features/objects-and-classes/anonymous-types.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-left-outer-joins.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-left-outer-joins.md index 6aa82a260add7..84cb03f28ce9c 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-left-outer-joins.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-perform-left-outer-joins.md @@ -1,74 +1,3 @@ --- -title: "How to: Perform Left Outer Joins (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "left outer joins [LINQ in C#]" - - "joins [C#], left outer" - - "query expressions [LINQ in C#], joins" - - "queries [LINQ in C#], joins" -ms.assetid: 18e32be8-93db-4d30-8dea-ec6596e18f43 -caps.latest.revision: 23 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "ru-ru" - - "zh-cn" - - "zh-tw" -translation.priority.mt: - - "cs-cz" - - "pl-pl" - - "pt-br" - - "tr-tr" +redirect_url: /dotnet/articles/csharp/linq/perform-left-outer-joins --- -# How to: Perform Left Outer Joins (C# Programming Guide) -A left outer join is a join in which each element of the first collection is returned, regardless of whether it has any correlated elements in the second collection. You can use [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)] to perform a left outer join by calling the method on the results of a group join. - -## Example - The following example demonstrates how to use the method on the results of a group join to perform a left outer join. - - The first step in producing a left outer join of two collections is to perform an inner join by using a group join. (See [How to: Perform Inner Joins](../../../csharp/programming-guide/linq-query-expressions/how-to-perform-inner-joins.md) for an explanation of this process.) In this example, the list of `Person` objects is inner-joined to the list of `Pet` objects based on a `Person` object that matches `Pet.Owner`. - - The second step is to include each element of the first (left) collection in the result set even if that element has no matches in the right collection. This is accomplished by calling on each sequence of matching elements from the group join. In this example, is called on each sequence of matching `Pet` objects. The method returns a collection that contains a single, default value if the sequence of matching `Pet` objects is empty for any `Person` object, thereby ensuring that each `Person` object is represented in the result collection. - -> [!NOTE] -> The default value for a reference type is `null`; therefore, the example checks for a null reference before accessing each element of each `Pet` collection. - - [!code-cs[CsLINQProgJoining#7](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/how-to-perform-left-outer-joins_1.cs)] - -## Compiling the Code - -- Create a new Console Application project in [!INCLUDE[vs_current_short](../../../csharp/programming-guide/classes-and-structs/includes/vs_current_short_md.md)]. - -- Add a reference to System.Core.dll if it is not already referenced. - -- Include the namespace. - -- Copy and paste the code from the example into the program.cs file, below the `Main` method in the `Program` class. Add a line of code to the `Main` method to call the `LeftOuterJoinExample` method. - -- Run the program. - -## See Also - - - [Join Operations](http://msdn.microsoft.com/library/442d176d-028c-4beb-8d22-407d4ef89107) - [How to: Perform Inner Joins](../../../csharp/programming-guide/linq-query-expressions/how-to-perform-inner-joins.md) - [How to: Perform Grouped Joins](../../../csharp/programming-guide/linq-query-expressions/how-to-perform-grouped-joins.md) - [Anonymous Types](../../../csharp/programming-guide/classes-and-structs/anonymous-types.md) - [Anonymous Types](../../../visual-basic/programming-guide/language-features/objects-and-classes/anonymous-types.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-query-a-collection-of-objects.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-query-a-collection-of-objects.md index 43d94bcca3138..70320703abdcc 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-query-a-collection-of-objects.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-query-a-collection-of-objects.md @@ -1,61 +1,3 @@ --- -title: "How to: Query a Collection of Objects (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "query expressions [LINQ in C#], object collections" - - "object collection querying [C#]" - - "queries [LINQ in C#], object collections" -ms.assetid: 122d1e3b-1604-4add-b6b4-b84530a77b6b -caps.latest.revision: 8 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/query-a-collection-of-objects --- -# How to: Query a Collection of Objects (C# Programming Guide) -This example shows how to perform a simple query over a list of `Student` objects. Each `Student` object contains some basic information about the student, and a list that represents the student's scores on four examinations. - - This application serves as the framework for many other examples in this section that use the same `students` data source. - -## Example - The following query returns the students who received a score of 90 or greater on their first exam. - - [!code-cs[csProgGuideLINQ#15](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-query-a-collection-of-objects_1.cs)] - - This query is intentionally simple to enable you to experiment. For example, you can try more predicates in the `where` clause, or use an `orderby` clause to sort the results. - -## Compiling the Code - -- Create a [!INCLUDE[vs_current_short](../../../csharp/programming-guide/classes-and-structs/includes/vs_current_short_md.md)] project that targets the .NET Framework version 3.5. By default, the project has a reference to System.Core.dll and a `using` directive for the System.Linq namespace. - -- Copy the code into your project. - -- Press F5 to compile and run the program. - -- Press any key to exit the console window. - -## See Also - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-return-a-query-from-a-method.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-return-a-query-from-a-method.md index 92c7232d282f7..b91abff46435a 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-return-a-query-from-a-method.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-return-a-query-from-a-method.md @@ -1,59 +1,3 @@ --- -title: "How to: Return a Query from a Method (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "queries [LINQ in C#], method returns query" - - "query expressions [LINQ in C#], method returns query" - - "method returns query [C#]" -ms.assetid: 9d6f20a7-f085-44cf-9df3-71948255ec68 -caps.latest.revision: 11 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/return-a-query-from-a-method --- -# How to: Return a Query from a Method (C# Programming Guide) -This example shows how to return a query from a method as the return value and as an `out` parameter. - - Any query must have a type of or , or a derived type such as . Therefore any return value or `out` parameter of a method that returns a query must also have that type. If a method materializes a query into a concrete or type, it is considered to be returning the query results instead of the query itself. A query variable that is returned from a method can still be composed or modified. - -## Example - In the following example, the first method returns a query as a return value, and the second method returns a query as an `out` parameter. Note that in both cases it is a query that is returned, not query results. - - [!code-cs[csProgGuideLINQ#80](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-return-a-query-from-a-method_1.cs)] - -## Compiling the Code - -- Create a [!INCLUDE[vs_current_short](../../../csharp/programming-guide/classes-and-structs/includes/vs_current_short_md.md)] project that targets the .NET Framework version 3.5 or a later version. By default, the project has a reference to System.Core.dll and a `using` directive for the System.Linq namespace. - -- Replace the class with the code in the example. - -- Press F5 to compile and run the program. - -- Press any key to exit the console window. - -## See Also - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-store-the-results-of-a-query-in-memory.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-store-the-results-of-a-query-in-memory.md index d376364a8fe67..d934390562142 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-store-the-results-of-a-query-in-memory.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-store-the-results-of-a-query-in-memory.md @@ -1,65 +1,3 @@ --- -title: "How to: Store the Results of a Query in Memory (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "LINQ query result storage [LINQ in C#]" - - "query expressions [LINQ in C#], storing results" -ms.assetid: 7271597f-3523-4f7b-b088-1eeffe913b2d -caps.latest.revision: 13 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "ru-ru" - - "zh-cn" - - "zh-tw" -translation.priority.mt: - - "cs-cz" - - "pl-pl" - - "pt-br" - - "tr-tr" +redirect_url: /dotnet/articles/csharp/linq/store-the-results-of-a-query-in-memory --- -# How to: Store the Results of a Query in Memory (C# Programming Guide) -A query is basically a set of instructions for how to retrieve and organize data. To execute the query requires a call to its method. This call is made when you use a `foreach` loop to iterate over the elements. To evaluate a query and store its results without executing a `foreach` loop, just call one of the following methods on the query variable: - -- - -- - -- - -- - - We recommend that when you store the query results, you assign the returned collection object to a new variable as shown in the following example: - -## Example - [!code-cs[csProgGuideLINQ#25](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-store-the-results-of-a-query-in-memory_1.cs)] - -## Compiling the Code - -- Create a [!INCLUDE[vs_current_short](../../../csharp/programming-guide/classes-and-structs/includes/vs_current_short_md.md)] project that targets the .NET Framework version 3.5. By default, the project has a reference to System.Core.dll and a `using` directive for the System.Linq namespace. - -- Copy the code into your project. - -- Press F5 to compile and run the program. - -- Press any key to exit the console window. - -## See Also - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/how-to-write-linq-queries.md b/docs/csharp/programming-guide/linq-query-expressions/how-to-write-linq-queries.md index 7e37a091e2459..d8b3d91e7216c 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/how-to-write-linq-queries.md +++ b/docs/csharp/programming-guide/linq-query-expressions/how-to-write-linq-queries.md @@ -1,114 +1,3 @@ --- -title: "How to: Write LINQ Queries in C# | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "query expressions [LINQ in C#], writing queries" - - "queries [LINQ in C#], writing" - - "writing LINQ queries" -ms.assetid: 45e47fcc-cfa1-4b72-b161-d038ae87bd23 -caps.latest.revision: 25 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/write-linq-queries --- -# How to: Write LINQ Queries in C# -This topic shows the three ways in which you can write a [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)] query in C#: - -1. Use query syntax. - -2. Use method syntax. - -3. Use a combination of query syntax and method syntax. - - The following examples demonstrate some simple [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)] queries by using each approach listed previously. In general, the rule is to use (1) whenever possible, and use (2) and (3) whenever necessary. - -> [!NOTE] -> These queries operate on simple in-memory collections; however, the basic syntax is identical to that used in [!INCLUDE[vbtecdlinq](../../../csharp/includes/vbtecdlinq_md.md)] and [!INCLUDE[sqltecxlinq](../../../csharp/programming-guide/concepts/linq/includes/sqltecxlinq_md.md)]. - -## Example - -## Query Syntax - The recommended way to write most queries is to use *query syntax* to create *query expressions*. The following example shows three query expressions. The first query expression demonstrates how to filter or restrict results by applying conditions with a `where` clause. It returns all elements in the source sequence whose values are greater than 7 or less than 3. The second expression demonstrates how to order the returned results. The third expression demonstrates how to group results according to a key. This query returns two groups based on the first letter of the word. - - [!code-cs[csProgGuideLINQ#5](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-write-linq-queries_1.cs)] - - Note that the type of the queries is . All of these queries could be written using `var` as shown in the following example: - - `var query = from num in numbers...` - - In each previous example, the queries do not actually execute until you iterate over the query variable in a `foreach` statement. For more information, see [Introduction to LINQ Queries (C#)](../../../csharp/programming-guide/concepts/linq/introduction-to-linq-queries.md). - -## Example - -## Method Syntax - Some query operations must be expressed as a method call. The most common such methods are those that return singleton numeric values, such as , , , , and so on. These methods must always be called last in any query because they represent only a single value and cannot serve as the source for an additional query operation. The following example shows a method call in a query expression: - - [!code-cs[csProgGuideLINQ#6](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-write-linq-queries_2.cs)] - -## Example - If the method has parameters, these are provided in the form of a [lambda](../../../csharp/programming-guide/statements-expressions-operators/lambda-expressions.md) expression, as shown in the following example: - - [!code-cs[csProgGuideLINQ#7](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-write-linq-queries_3.cs)] - - In the previous queries, only Query #4 executes immediately. This is because it returns a single value, and not a generic collection. The method itself has to use `foreach` in order to compute its value. - - Each of the previous queries can be written by using implicit typing with [var](../../../csharp/language-reference/keywords/var.md), as shown in the following example: - - [!code-cs[csProgGuideLINQ#8](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-write-linq-queries_4.cs)] - -## Example - -## Mixed Query and Method Syntax - This example shows how to use method syntax on the results of a query clause. Just enclose the query expression in parentheses, and then apply the dot operator and call the method. In the following example, query #7 returns a count of the numbers whose value is between 3 and 7. In general, however, it is better to use a second variable to store the result of the method call. In this manner, the query is less likely to be confused with the results of the query. - - [!code-cs[csProgGuideLINQ#9](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-write-linq-queries_5.cs)] - - Because Query #7 returns a single value and not a collection, the query executes immediately. - - The previous query can be written by using implicit typing with `var`, as follows: - -``` -var numCount = (from num in numbers... -``` - - It can be written in method syntax as follows: - -``` -var numCount = numbers.Where(n => n < 3 || n > 7).Count(); -``` - - It can be written by using explicit typing, as follows: - -``` -int numCount = numbers.Where(n => n < 3 || n > 7).Count(); -``` - -## See Also - [LINQ (Language-Integrated Query)](http://msdn.microsoft.com/library/a73c4aec-5d15-4e98-b962-1274021ea93d) - [Walkthrough: Writing Queries in C#](../../../csharp/programming-guide/concepts/linq/walkthrough-writing-queries-linq.md) - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) - [where clause](../../../csharp/language-reference/keywords/where-clause.md) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/index.md b/docs/csharp/programming-guide/linq-query-expressions/index.md index e11b4f2c4fdcb..93f57c936a0b9 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/index.md +++ b/docs/csharp/programming-guide/linq-query-expressions/index.md @@ -1,103 +1,3 @@ --- -title: "LINQ Query Expressions (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "expressions [C#], LINQ query expressions" - - "queries [LINQ in C#], query expressions" - - "LINQ [C#], query expressions" - - "query expressions [LINQ in C#]" - - "C# Language, LINQ query expressions" -ms.assetid: 40638f19-fb46-4d26-a2d9-a383b48f5ed4 -caps.latest.revision: 21 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/index --- -# LINQ Query Expressions (C# Programming Guide) -[!INCLUDE[vbteclinqext](../../../csharp/getting-started/includes/vbteclinqext_md.md)] is the name for a set of technologies based on the integration of query capabilities directly into the C# language (also in Visual Basic and potentially any other .NET language). With [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)], a query is now a first-class language construct, just like classes, methods, events and so on. - - For a developer who writes queries, the most visible "language-integrated" part of [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)] is the query expression. Query expressions are written in a declarative *query syntax* introduced in C# 3.0. By using query syntax, you can perform even complex filtering, ordering, and grouping operations on data sources with a minimum of code. You use the same basic query expression patterns to query and transform data in SQL databases, [!INCLUDE[vstecado](../../../csharp/programming-guide/concepts/linq/includes/vstecado_md.md)] Datasets, XML documents and streams, and .NET collections. - - The following example shows the complete query operation. The complete operation includes creating a data source, defining the query expression, and executing the query in a `foreach` statement. - - [!code-cs[csProgGuideLINQ#11](../../../csharp/programming-guide/arrays/codesnippet/CSharp/index_1.cs)] - - For more information about the basics of [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)] in C#, see [Getting Started with LINQ in C#](../../../csharp/programming-guide/concepts/linq/getting-started-with-linq.md). - -## Query Expression Overview - -- Query expressions can be used to query and to transform data from any [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)]-enabled data source. For example, a single query can retrieve data from a SQL database, and produce an XML stream as output. - -- Query expressions are easy to master because they use many familiar C# language constructs. For more information, see [Getting Started with LINQ in C#](../../../csharp/programming-guide/concepts/linq/getting-started-with-linq.md). - -- The variables in a query expression are all strongly typed, although in many cases you do not have to provide the type explicitly because the compiler can infer it. For more information, see [Type Relationships in LINQ Query Operations](../../../csharp/programming-guide/concepts/linq/type-relationships-in-linq-query-operations.md). - -- A query is not executed until you iterate over the query variable in a `foreach` statement. For more information, see [Introduction to LINQ Queries (C#)](../../../csharp/programming-guide/concepts/linq/introduction-to-linq-queries.md). - -- At compile time, query expressions are converted to Standard Query Operator method calls according to the rules set forth in the C# specification. Any query that can be expressed by using query syntax can also be expressed by using method syntax. However, in most cases query syntax is more readable and concise. For more information, see [C# Language Specification](../../../csharp/language-reference/language-specification.md) and [Standard Query Operators Overview](../../../csharp/programming-guide/concepts/linq/standard-query-operators-overview.md). - -- As a rule when you write [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)] queries, we recommend that you use query syntax whenever possible and method syntax whenever necessary. There is no semantic or performance difference between the two different forms. Query expressions are often more readable than equivalent expressions written in method syntax. - -- Some query operations, such as or , have no equivalent query expression clause and must therefore be expressed as a method call. Method syntax can be combined with query syntax in various ways. For more information, see [Query Syntax and Method Syntax in LINQ](../../../csharp/programming-guide/concepts/linq/query-syntax-and-method-syntax-in-linq.md). - -- Query expressions can be compiled to expression trees or to delegates, depending on the type that the query is applied to. queries are compiled to delegates. and queries are compiled to expression trees. For more information, see [Expression Trees](../../../csharp/programming-guide/concepts/expression-trees/index.md). - - The following table lists topics that provide additional information about queries and code examples for common tasks. - -|Topic|Description| -|-----------|-----------------| -|[Query Expression Basics](../../../csharp/programming-guide/linq-query-expressions/query-expression-basics.md)|Introduces fundamental query concepts and provides examples of C# query syntax.| -|[How to: Write LINQ Queries in C#](../../../csharp/programming-guide/linq-query-expressions/how-to-write-linq-queries.md)|Provides examples of several basic types of query expressions.| -|[How to: Handle Exceptions in Query Expressions](../../../csharp/programming-guide/linq-query-expressions/how-to-handle-exceptions-in-query-expressions.md)|How and when to move potential exception-throwing code outside a query expression.| -|[How to: Populate Object Collections from Multiple Sources (LINQ)](../../../csharp/programming-guide/concepts/linq/how-to-populate-object-collections-from-multiple-sources-linq.md)|How to use the `select` statement to merge data from different sources into a new type.| -|[How to: Group Query Results](../../../csharp/programming-guide/linq-query-expressions/how-to-group-query-results.md)|Shows different ways to use the `group` clause.| -|[How to: Create a Nested Group](../../../csharp/programming-guide/linq-query-expressions/how-to-create-a-nested-group.md)|Shows how to create nested groups.| -|[How to: Perform a Subquery on a Grouping Operation](../../../csharp/programming-guide/linq-query-expressions/how-to-perform-a-subquery-on-a-grouping-operation.md)|Shows how to use a sub-expression in a query as a data source for a new query.| -|[How to: Group Results by Contiguous Keys](../../../csharp/programming-guide/linq-query-expressions/how-to-group-results-by-contiguous-keys.md)|Shows how to implement a thread-safe standard query operator that can perform grouping operations on streaming data sources.| -|[How to: Dynamically Specify Predicate Filters at Runtime](../../../csharp/programming-guide/linq-query-expressions/how-to-dynamically-specify-predicate-filters-at-runtime.md)|Shows how to supply an arbitrary number of values to use in equality comparisons in a `where` clause.| -|[How to: Store the Results of a Query in Memory](../../../csharp/programming-guide/linq-query-expressions/how-to-store-the-results-of-a-query-in-memory.md)|Illustrates how to materialize and store query results without necessarily using a `foreach` loop.| -|[How to: Return a Query from a Method](../../../csharp/programming-guide/linq-query-expressions/how-to-return-a-query-from-a-method.md)|Shows how to return query variables from methods, and how to pass them to methods as input parameters.| -|[How to: Perform Custom Join Operations](../../../csharp/programming-guide/linq-query-expressions/how-to-perform-custom-join-operations.md)|Shows how to perform join operations based on any kind of predicate function.| -|[How to: Join by Using Composite Keys](../../../csharp/programming-guide/linq-query-expressions/how-to-join-by-using-composite-keys.md)|Shows how to join two sources based on more than one matching key.| -|[How to: Order the Results of a Join Clause](../../../csharp/programming-guide/linq-query-expressions/how-to-order-the-results-of-a-join-clause.md)|Shows how to order a sequence that is produced by a join operation.| -|[How to: Perform Inner Joins](../../../csharp/programming-guide/linq-query-expressions/how-to-perform-inner-joins.md)|Shows how to perform an inner join in [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)].| -|[How to: Perform Grouped Joins](../../../csharp/programming-guide/linq-query-expressions/how-to-perform-grouped-joins.md)|Shows how to produce a grouped join in [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)].| -|[How to: Perform Left Outer Joins](../../../csharp/programming-guide/linq-query-expressions/how-to-perform-left-outer-joins.md)|Shows how to produce a left outer join in [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)].| -|[How to: Handle Null Values in Query Expressions](../../../csharp/programming-guide/linq-query-expressions/how-to-handle-null-values-in-query-expressions.md)|Shows how to handle null values in [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)] queries.| - -## See Also - [C# Programming Guide](../../../csharp/programming-guide/index.md) - [LINQ (Language-Integrated Query)](../../../csharp/programming-guide/concepts/linq/index.md) - [Walkthrough: Writing Queries in C#](../../../csharp/programming-guide/concepts/linq/walkthrough-writing-queries-linq.md) - [Basic LINQ Query Operations](../../../csharp/programming-guide/concepts/linq/basic-linq-query-operations.md) - [Query Syntax and Method Syntax in LINQ](../../../csharp/programming-guide/concepts/linq/query-syntax-and-method-syntax-in-linq.md) - [Standard Query Operators Overview](../../../csharp/programming-guide/concepts/linq/standard-query-operators-overview.md) - [Query Keywords (LINQ)](../../../csharp/language-reference/keywords/query-keywords.md) - [How Linq to Objects Queries Work](http://go.microsoft.com/fwlink/?LinkId=112389) - [Reading and Writing Queries](http://go.microsoft.com/fwlink/?LinkId=112391) - [What is a collection?](http://go.microsoft.com/fwlink/?LinkId=112394) - [Link to Everything: A List of LINQ Providers](http://go.microsoft.com/fwlink/?LinkId=112411) \ No newline at end of file diff --git a/docs/csharp/programming-guide/linq-query-expressions/query-expression-basics.md b/docs/csharp/programming-guide/linq-query-expressions/query-expression-basics.md index 7e37a2e47e75f..0397a298c2187 100644 --- a/docs/csharp/programming-guide/linq-query-expressions/query-expression-basics.md +++ b/docs/csharp/programming-guide/linq-query-expressions/query-expression-basics.md @@ -1,190 +1,3 @@ --- -title: "Query Expression Basics (C# Programming Guide) | Microsoft Docs" - -ms.date: "2015-07-20" -ms.prod: .net - - -ms.technology: - - "devlang-csharp" - -ms.topic: "article" -dev_langs: - - "CSharp" -helpviewer_keywords: - - "query expressions [LINQ in C#], query execution" - - "query expressions [LINQ in C#], basics" - - "queries [LINQ in C#], basics" -ms.assetid: d3e1f4e6-1cf0-4066-87e3-1a42387223a6 -caps.latest.revision: 32 -author: "BillWagner" -ms.author: "wiwagn" - -translation.priority.ht: - - "cs-cz" - - "de-de" - - "es-es" - - "fr-fr" - - "it-it" - - "ja-jp" - - "ko-kr" - - "pl-pl" - - "pt-br" - - "ru-ru" - - "tr-tr" - - "zh-cn" - - "zh-tw" +redirect_url: /dotnet/articles/csharp/linq/query-expression-basics --- -# Query Expression Basics (C# Programming Guide) -## What Is a Query and What Does It Do? - A *query* is a set of instructions that describes what data to retrieve from a given data source (or sources) and what shape and organization the returned data should have. A query is distinct from the results that it produces. - - Generally, the source data is organized logically as a sequence of elements of the same kind. A SQL database table contains a sequence of rows. Similarly, an [!INCLUDE[vstecado](../../../csharp/programming-guide/concepts/linq/includes/vstecado_md.md)] contains a sequence of objects. In an XML file, there is a "sequence" of XML elements (although these are organized hierarchically in a tree structure). An in-memory collection contains a sequence of objects. - - From an application's viewpoint, the specific type and structure of the original source data is not important. The application always sees the source data as an or collection. In [!INCLUDE[sqltecxlinq](../../../csharp/programming-guide/concepts/linq/includes/sqltecxlinq_md.md)], the source data is made visible as an `IEnumerable`\<>. In [!INCLUDE[linq_dataset](../../../csharp/programming-guide/concepts/linq/includes/linq_dataset_md.md)], it is an `IEnumerable`\<>. In [!INCLUDE[vbtecdlinq](../../../csharp/includes/vbtecdlinq_md.md)], it is an `IEnumerable` or `IQueryable` of whatever custom objects you have defined to represent the data in the SQL table. - - Given this source sequence, a query may do one of three things: - -- Retrieve a subset of the elements to produce a new sequence without modifying the individual elements. The query may then sort or group the returned sequence in various ways, as shown in the following example (assume `scores` is an `int[]`): - - [!code-cs[csrefQueryExpBasics#45](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_1.cs)] - -- Retrieve a sequence of elements as in the previous example but transform them to a new type of object. For example, a query may retrieve only the last names from certain customer records in a data source. Or it may retrieve the complete record and then use it to construct another in-memory object type or even XML data before generating the final result sequence. The following example shows a transform from an `int` to a `string`. Note the new type of `highScoresQuery`. - - [!code-cs[csrefQueryExpBasics#46](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_2.cs)] - -- Retrieve a singleton value about the source data, such as: - - - The number of elements that match a certain condition. - - - The element that has the greatest or least value. - - - The first element that matches a condition, or the sum of particular values in a specified set of elements. For example, the following query returns the number of scores greater than 80 from the `scores` integer array: - - [!code-cs[csrefQueryExpBasics#47](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_3.cs)] - - In the previous example, note the use of parentheses around the query expression before the call to the `Count` method. You can also express this by using a new variable to store the concrete result. This technique is more readable because it keeps the variable that store the query separate from the query that stores a result. - - [!code-cs[csrefQueryExpBasics#48](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_4.cs)] - - In the previous example, the query is executed in the call to `Count`, because `Count` must iterate over the results in order to determine the number of elements returned by `highScoresQuery`. - -## What Is a Query Expression? - A *query expression* is a query expressed in query syntax. A query expression is a first-class language construct. It is just like any other expression and can be used in any context in which a C# expression is valid. A query expression consists of a set of clauses written in a declarative syntax similar to SQL or XQuery. Each clause in turn contains one or more C# expressions, and these expressions may themselves be either a query expression or contain a query expression. - - A query expression must begin with a [from](../../../csharp/language-reference/keywords/from-clause.md) clause and must end with a [select](../../../csharp/language-reference/keywords/select-clause.md) or [group](../../../csharp/language-reference/keywords/group-clause.md) clause. Between the first `from` clause and the last `select` or `group` clause, it can contain one or more of these optional clauses: [where](../../../csharp/language-reference/keywords/where-clause.md), [orderby](../../../csharp/language-reference/keywords/orderby-clause.md), [join](../../../csharp/language-reference/keywords/join-clause.md), [let](../../../csharp/language-reference/keywords/let-clause.md) and even additional [from](../../../csharp/language-reference/keywords/from-clause.md) clauses. You can also use the [into](../../../csharp/language-reference/keywords/into.md) keyword to enable the result of a `join` or `group` clause to serve as the source for additional query clauses in the same query expression. - -### Query Variable - In [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)], a query variable is any variable that stores a *query* instead of the *results* of a query. More specifically, a query variable is always an enumerable type that will produce a sequence of elements when it is iterated over in a `foreach` statement or a direct call to its `IEnumerator.MoveNext` method. - - The following code example shows a simple query expression with one data source, one filtering clause, one ordering clause, and no transformation of the source elements. The `select` clause ends the query. - - [!code-cs[csrefQueryExpBasics#49](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_5.cs)] - - In the previous example, `scoreQuery` is a *query variable,* which is sometimes referred to as just a *query*. The query variable stores no actual result data, which is produced in the `foreach` loop. And when the `foreach` statement executes, the query results are not returned through the query variable `scoreQuery`. Rather, they are returned through the iteration variable `testScore`. The `scoreQuery` variable can be iterated in a second `foreach` loop. It will produce the same results as long as neither it nor the data source has been modified. - - A query variable may store a query that is expressed in query syntax or method syntax, or a combination of the two. In the following examples, both `queryMajorCities` and `queryMajorCities2` are query variables: - - [!code-cs[csrefQueryExpBasics#50](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_6.cs)] - - On the other hand, the following two examples show variables that are not query variables even through each is initialized with a query. They are not query variables because they store results: - - [!code-cs[csrefQueryExpBasics#51](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_7.cs)] - -> [!NOTE] -> In the [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)] documentation, variables that store a query have the word "query" as part of their names. Variables that store an actual result do not have "query" in their names. - - For more information about the different ways to express queries, see [Query Syntax and Method Syntax in LINQ](../../../csharp/programming-guide/concepts/linq/query-syntax-and-method-syntax-in-linq.md). - -#### Explicit and Implicit Typing of Query Variables - This documentation usually provides the explicit type of the query variable in order to show the type relationship between the query variable and the [select clause](../../../csharp/language-reference/keywords/select-clause.md). However, you can also use the [var](../../../csharp/language-reference/keywords/var.md) keyword to instruct the compiler to infer the type of a query variable (or any other local variable) at compile time. For example, the query example that was shown previously in this topic can also be expressed by using implicit typing: - - [!code-cs[csrefQueryExpBasics#52](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_8.cs)] - - For more information, see [Implicitly Typed Local Variables](../../../csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables.md) and [Type Relationships in LINQ Query Operations](../../../csharp/programming-guide/concepts/linq/type-relationships-in-linq-query-operations.md). - -### Starting a Query Expression - A query expression must begin with a `from` clause. It specifies a data source together with a range variable. The range variable represents each successive element in the source sequence as the source sequence is being traversed. The range variable is strongly typed based on the type of elements in the data source. In the following example, because `countries` is an array of `Country` objects, the range variable is also typed as `Country`. Because the range variable is strongly typed, you can use the dot operator to access any available members of the type. - - [!code-cs[csrefQueryExpBasics#53](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_9.cs)] - - The range variable is in scope until the query is exited either with a semicolon or with a *continuation* clause. - - A query expression may contain multiple `from` clauses. Use additional `from` clauses when each element in the source sequence is itself a collection or contains a collection. For example, assume that you have a collection of `Country` objects, each of which contains a collection of `City` objects named `Cities`. To query the `City` objects in each `Country`, use two `from` clauses as shown here: - - [!code-cs[csrefQueryExpBasics#54](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_10.cs)] - - For more information, see [from clause](../../../csharp/language-reference/keywords/from-clause.md). - -### Ending a Query Expression - A query expression must end with either a `select` clause or a `group` clause. - -#### group Clause - Use the `group` clause to produce a sequence of groups organized by a key that you specify. The key can be any data type. For example, the following query creates a sequence of groups that contains one or more `Country` objects and whose key is a `char` value. - - [!code-cs[csrefQueryExpBasics#55](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_11.cs)] - - For more information about grouping, see [group clause](../../../csharp/language-reference/keywords/group-clause.md). - -#### select Clause - Use the `select` clause to produce all other types of sequences. A simple `select` clause just produces a sequence of the same type of objects as the objects that are contained in the data source. In this example, the data source contains `Country` objects. The `orderby` clause just sorts the elements into a new order and the `select` clause produces a sequence of the reordered `Country` objects. - - [!code-cs[csrefQueryExpBasics#56](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_12.cs)] - - The `select` clause can be used to transform source data into sequences of new types. This transformation is also named a *projection*. In the following example, the `select` clause *projects* a sequence of anonymous types which contains only a subset of the fields in the original element. Note that the new objects are initialized by using an object initializer. - - [!code-cs[csrefQueryExpBasics#57](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_13.cs)] - - For more information about all the ways that a `select` clause can be used to transform source data, see [select clause](../../../csharp/language-reference/keywords/select-clause.md). - -#### Continuations with "into" - You can use the `into` keyword in a `select` or `group` clause to create a temporary identifier that stores a query. Do this when you must perform additional query operations on a query after a grouping or select operation. In the following example `countries` are grouped according to population in ranges of 10 million. After these groups are created, additional clauses filter out some groups, and then to sort the groups in ascending order. To perform those additional operations, the continuation represented by `countryGroup` is required. - - [!code-cs[csrefQueryExpBasics#58](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_14.cs)] - - For more information, see [into](../../../csharp/language-reference/keywords/into.md). - -### Filtering, Ordering, and Joining - Between the starting `from` clause, and the ending `select` or `group` clause, all other clauses (`where`, `join`, `orderby`, `from`, `let`) are optional. Any of the optional clauses may be used zero times or multiple times in a query body. - -#### where Clause - Use the `where` clause to filter out elements from the source data based on one or more predicate expressions. The `where` clause in the following example has two predicates. - - [!code-cs[csrefQueryExpBasics#59](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_15.cs)] - - For more information, see [where clause](../../../csharp/language-reference/keywords/where-clause.md). - -#### orderby Clause - Use the `orderby` clause to sort the results in either ascending or descending order. You can also specify secondary sort orders. The following example performs a primary sort on the `country` objects by using the `Area` property. It then performs a secondary sort by using the `Population` property. - - [!code-cs[csrefQueryExpBasics#60](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_16.cs)] - - The `ascending` keyword is optional; it is the default sort order if no order is specified. For more information, see [orderby clause](../../../csharp/language-reference/keywords/orderby-clause.md). - -#### join Clause - Use the `join` clause to associate and/or combine elements from one data source with elements from another data source based on an equality comparison between specified keys in each element. In [!INCLUDE[vbteclinq](../../../csharp/includes/vbteclinq_md.md)], join operations are performed on sequences of objects whose elements are different types. After you have joined two sequences, you must use a `select` or `group` statement to specify which element to store in the output sequence. You can also use an anonymous type to combine properties from each set of associated elements into a new type for the output sequence. The following example associates `prod` objects whose `Category` property matches one of the categories in the `categories` string array. Products whose `Category` does not match any string in `categories` are filtered out. The `select` statement projects a new type whose properties are taken from both `cat` and `prod`. - - [!code-cs[csrefQueryExpBasics#61](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_17.cs)] - - You can also perform a group join by storing the results of the `join` operation into a temporary variable by using the [into](../../../csharp/language-reference/keywords/into.md) keyword. For more information, see [join clause](../../../csharp/language-reference/keywords/join-clause.md). - -#### let Clause - Use the `let` clause to store the result of an expression, such as a method call, in a new range variable. In the following example, the range variable `firstName` stores the first element of the array of strings that is returned by `Split`. - - [!code-cs[csrefQueryExpBasics#62](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_18.cs)] - - For more information, see [let clause](../../../csharp/language-reference/keywords/let-clause.md). - -### Subqueries in a Query Expression - A query clause may itself contain a query expression, which is sometimes referred to as a *subquery*. Each subquery starts with its own `from` clause that does not necessarily point to the same data source in the first `from` clause. For example, the following query shows a query expression that is used in the select statement to retrieve the results of a grouping operation. - - [!code-cs[csrefQueryExpBasics#63](../../../csharp/programming-guide/linq-query-expressions/codesnippet/CSharp/query-expression-basics_19.cs)] - - For more information, see [How to: Perform a Subquery on a Grouping Operation](../../../csharp/programming-guide/linq-query-expressions/how-to-perform-a-subquery-on-a-grouping-operation.md). - -## See Also - [C# Programming Guide](../../../csharp/programming-guide/index.md) - [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) - [LINQ (Language-Integrated Query)](http://msdn.microsoft.com/library/a73c4aec-5d15-4e98-b962-1274021ea93d) - [Query Keywords (LINQ)](../../../csharp/language-reference/keywords/query-keywords.md) - [Standard Query Operators Overview](http://msdn.microsoft.com/library/24cda21e-8af8-4632-b519-c404a839b9b2) \ No newline at end of file diff --git a/docs/toc.md b/docs/toc.md index 01958780cf04c..aca3c9b756c8b 100644 --- a/docs/toc.md +++ b/docs/toc.md @@ -276,7 +276,26 @@ #### [The .NET Event Pattern](csharp/event-pattern.md) #### [The Updated .NET Event Pattern](csharp/modern-events.md) #### [Distinguishing Delegates and Events](csharp/distinguish-delegates-events.md) -### [🔧 Language Integrated Query (LINQ)](csharp/linq.md) +### [Language Integrated Query (LINQ)](csharp/linq/index.md) +####[Query expression basics](csharp/linq/query-expression-basics.md) +####[LINQ in C#](csharp/linq/linq-in-csharp.md) +####[Write LINQ queries in C#](csharp/linq/write-linq-queries.md) +####[Query a collection of objects](csharp/linq/query-a-collection-of-objects.md) +####[Return a query from a method](csharp/linq/return-a-query-from-a-method.md) +####[Store the results of a query in memory](csharp/linq/store-the-results-of-a-query-in-memory.md) +####[Group query results](csharp/linq/group-query-results.md) +####[Create a nested group](csharp/linq/create-a-nested-group.md) +####[Perform a subquery on a grouping operation](csharp/linq/perform-a-subquery-on-a-grouping-operation.md) +####[Group results by contiguous keys](csharp/linq/group-results-by-contiguous-keys.md) +####[Dynamically specify predicate filters at runtime](csharp/linq/dynamically-specify-predicate-filters-at-runtime.md) +####[Perform inner joins](csharp/linq/perform-inner-joins.md) +####[Perform grouped joins](csharp/linq/perform-grouped-joins.md) +####[Perform left outer joins](csharp/linq/perform-left-outer-joins.md) +####[Order the results of a join clause](csharp/linq/order-the-results-of-a-join-clause.md) +####[Join by using composite keys](csharp/linq/join-by-using-composite-keys.md) +####[Perform custom join operations](csharp/linq/perform-custom-join-operations.md) +####[Handle null values in query expressions](csharp/linq/handle-null-values-in-query-expressions.md) +####[Handle exceptions in query expressions](csharp/linq/handle-exceptions-in-query-expressions.md) ### [Asynchronous programming](csharp/async.md) ### [🔧 Parallel programming](csharp/parallel.md) ### [🔧 Pattern Matching](csharp/pattern-matching.md) diff --git a/samples/snippets/csharp/concepts/linq/how-to-create-a-nested-group_1.cs b/samples/snippets/csharp/concepts/linq/how-to-create-a-nested-group_1.cs new file mode 100644 index 0000000000000..19bd45e5053bc --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-create-a-nested-group_1.cs @@ -0,0 +1,57 @@ + public void QueryNestedGroups() + { + var queryNestedGroups = + from student in students + group student by student.Year into newGroup1 + from newGroup2 in + (from student in newGroup1 + group student by student.LastName) + group newGroup2 by newGroup1.Key; + + // Three nested foreach loops are required to iterate + // over all elements of a grouped group. Hover the mouse + // cursor over the iteration variables to see their actual type. + foreach (var outerGroup in queryNestedGroups) + { + Console.WriteLine($"DataClass.Student Level = {outerGroup.Key}"); + foreach (var innerGroup in outerGroup) + { + Console.WriteLine($"\tNames that begin with: {innerGroup.Key}"); + foreach (var innerGroupElement in innerGroup) + { + Console.WriteLine("\t\t{innerGroupElement.LastName} {innerGroupElement.FirstName}"); + } + } + } + } + /* + Output: + DataClass.Student Level = SecondYear + Names that begin with: Adams + Adams Terry + Names that begin with: Garcia + Garcia Hugo + Names that begin with: Omelchenko + Omelchenko Svetlana + DataClass.Student Level = ThirdYear + Names that begin with: Fakhouri + Fakhouri Fadi + Names that begin with: Garcia + Garcia Debra + Names that begin with: Tucker + Tucker Lance + DataClass.Student Level = FirstYear + Names that begin with: Feng + Feng Hanying + Names that begin with: Mortensen + Mortensen Sven + Names that begin with: Tucker + Tucker Michael + DataClass.Student Level = FourthYear + Names that begin with: Garcia + Garcia Cesar + Names that begin with: O'Donnell + O'Donnell Claire + Names that begin with: Zabokritski + Zabokritski Eugene + */ \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-dynamically-specify-predicate-filters-at-runtime_1.cs b/samples/snippets/csharp/concepts/linq/how-to-dynamically-specify-predicate-filters-at-runtime_1.cs new file mode 100644 index 0000000000000..e2d001cc3f4f2 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-dynamically-specify-predicate-filters-at-runtime_1.cs @@ -0,0 +1,24 @@ + class DynamicPredicates : StudentClass + { + static void Main(string[] args) + { + string[] ids = { "111", "114", "112" }; + + Console.WriteLine("Press any key to exit."); + Console.ReadKey(); + } + + static void QueryByID(string[] ids) + { + var queryNames = + from student in students + let i = student.ID.ToString() + where ids.Contains(i) + select new { student.LastName, student.ID }; + + foreach (var name in queryNames) + { + Console.WriteLine($"{name.LastName}: {name.ID}"); + } + } + } \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-dynamically-specify-predicate-filters-at-runtime_2.cs b/samples/snippets/csharp/concepts/linq/how-to-dynamically-specify-predicate-filters-at-runtime_2.cs new file mode 100644 index 0000000000000..797729ab9a42e --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-dynamically-specify-predicate-filters-at-runtime_2.cs @@ -0,0 +1,41 @@ + // To run this sample, first specify an integer value of 1 to 4 for the command + // line. This number will be converted to a GradeLevel value that specifies which + // set of students to query. + // Call the method: QueryByYear(args[0]); + + static void QueryByYear(string level) + { + GradeLevel year = (GradeLevel)Convert.ToInt32(level); + IEnumerable studentQuery = null; + switch (year) + { + case GradeLevel.FirstYear: + studentQuery = from student in students + where student.Year == GradeLevel.FirstYear + select student; + break; + case GradeLevel.SecondYear: + studentQuery = from student in students + where student.Year == GradeLevel.SecondYear + select student; + break; + case GradeLevel.ThirdYear: + studentQuery = from student in students + where student.Year == GradeLevel.ThirdYear + select student; + break; + case GradeLevel.FourthYear: + studentQuery = from student in students + where student.Year == GradeLevel.FourthYear + select student; + break; + + default: + break; + } + Console.WriteLine("The following students are at level {0}", year.ToString()); + foreach (Student name in studentQuery) + { + Console.WriteLine($"{name.LastName}: {name.ID}"); + } + } \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-group-query-results_1.cs b/samples/snippets/csharp/concepts/linq/how-to-group-query-results_1.cs new file mode 100644 index 0000000000000..c56e957b8975b --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-group-query-results_1.cs @@ -0,0 +1,88 @@ + public class StudentClass + { + #region data + protected enum GradeLevel { FirstYear = 1, SecondYear, ThirdYear, FourthYear }; + protected class Student + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int ID { get; set; } + public GradeLevel Year; + public List ExamScores; + } + + protected static List students = new List + { + new Student {FirstName = "Terry", LastName = "Adams", ID = 120, + Year = GradeLevel.SecondYear, + ExamScores = new List{ 99, 82, 81, 79}}, + new Student {FirstName = "Fadi", LastName = "Fakhouri", ID = 116, + Year = GradeLevel.ThirdYear, + ExamScores = new List{ 99, 86, 90, 94}}, + new Student {FirstName = "Hanying", LastName = "Feng", ID = 117, + Year = GradeLevel.FirstYear, + ExamScores = new List{ 93, 92, 80, 87}}, + new Student {FirstName = "Cesar", LastName = "Garcia", ID = 114, + Year = GradeLevel.FourthYear, + ExamScores = new List{ 97, 89, 85, 82}}, + new Student {FirstName = "Debra", LastName = "Garcia", ID = 115, + Year = GradeLevel.ThirdYear, + ExamScores = new List{ 35, 72, 91, 70}}, + new Student {FirstName = "Hugo", LastName = "Garcia", ID = 118, + Year = GradeLevel.SecondYear, + ExamScores = new List{ 92, 90, 83, 78}}, + new Student {FirstName = "Sven", LastName = "Mortensen", ID = 113, + Year = GradeLevel.FirstYear, + ExamScores = new List{ 88, 94, 65, 91}}, + new Student {FirstName = "Claire", LastName = "O'Donnell", ID = 112, + Year = GradeLevel.FourthYear, + ExamScores = new List{ 75, 84, 91, 39}}, + new Student {FirstName = "Svetlana", LastName = "Omelchenko", ID = 111, + Year = GradeLevel.SecondYear, + ExamScores = new List{ 97, 92, 81, 60}}, + new Student {FirstName = "Lance", LastName = "Tucker", ID = 119, + Year = GradeLevel.ThirdYear, + ExamScores = new List{ 68, 79, 88, 92}}, + new Student {FirstName = "Michael", LastName = "Tucker", ID = 122, + Year = GradeLevel.FirstYear, + ExamScores = new List{ 94, 92, 91, 91}}, + new Student {FirstName = "Eugene", LastName = "Zabokritski", ID = 121, + Year = GradeLevel.FourthYear, + ExamScores = new List{ 96, 85, 91, 60}} + }; + #endregion + + //Helper method, used in GroupByRange. + protected static int GetPercentile(Student s) + { + double avg = s.ExamScores.Average(); + return avg > 0 ? (int)avg / 10 : 0; + } + + + + public void QueryHighScores(int exam, int score) + { + var highScores = from student in students + where student.ExamScores[exam] > score + select new {Name = student.FirstName, Score = student.ExamScores[exam]}; + + foreach (var item in highScores) + { + Console.WriteLine($"{item.Name:-15}{item.Score}"); + } + } + } + + public class Program + { + public static void Main() + { + StudentClass sc = new StudentClass(); + sc.QueryHighScores(1, 90); + + // Keep the console window open in debug mode. + Console.WriteLine("Press any key to exit"); + Console.ReadKey(); + } + } \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-group-query-results_2.cs b/samples/snippets/csharp/concepts/linq/how-to-group-query-results_2.cs new file mode 100644 index 0000000000000..62d16a652960b --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-group-query-results_2.cs @@ -0,0 +1,45 @@ + public void GroupBySingleProperty() + { + Console.WriteLine("Group by a single property in an object:"); + + // Variable queryLastNames is an IEnumerable>. + var queryLastNames = + from student in students + group student by student.LastName into newGroup + orderby newGroup.Key + select newGroup; + + foreach (var nameGroup in queryLastNames) + { + Console.WriteLine("Key: {0}", nameGroup.Key); + foreach (var student in nameGroup) + { + Console.WriteLine("\t{student.LastName}, {student.FirstName}"); + } + } + } + /* Output: + Group by a single property in an object: + Key: Adams + Adams, Terry + Key: Fakhouri + Fakhouri, Fadi + Key: Feng + Feng, Hanying + Key: Garcia + Garcia, Cesar + Garcia, Debra + Garcia, Hugo + Key: Mortensen + Mortensen, Sven + Key: O'Donnell + O'Donnell, Claire + Key: Omelchenko + Omelchenko, Svetlana + Key: Tucker + Tucker, Lance + Tucker, Michael + Key: Zabokritski + Zabokritski, Eugene + */ \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-group-query-results_3.cs b/samples/snippets/csharp/concepts/linq/how-to-group-query-results_3.cs new file mode 100644 index 0000000000000..c980e5a776a38 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-group-query-results_3.cs @@ -0,0 +1,40 @@ + public void GroupBySubstring() + { + Console.WriteLine("\r\nGroup by something other than a property of the object:"); + + var queryFirstLetters = + from student in students + group student by student.LastName[0]; + + foreach (var studentGroup in queryFirstLetters) + { + Console.WriteLine($"Key: {studentGroup.Key}"); + // Nested foreach is required to access group items. + foreach (var student in studentGroup) + { + Console.WriteLine("\t{student.LastName}, {student.FirstName}"); + } + } + } + /* Output: + Group by something other than a property of the object: + Key: A + Adams, Terry + Key: F + Fakhouri, Fadi + Feng, Hanying + Key: G + Garcia, Cesar + Garcia, Debra + Garcia, Hugo + Key: M + Mortensen, Sven + Key: O + O'Donnell, Claire + Omelchenko, Svetlana + Key: T + Tucker, Lance + Tucker, Michael + Key: Z + Zabokritski, Eugene + */ \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-group-query-results_4.cs b/samples/snippets/csharp/concepts/linq/how-to-group-query-results_4.cs new file mode 100644 index 0000000000000..40ebbdd1fafc6 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-group-query-results_4.cs @@ -0,0 +1,6 @@ + //Helper method, used in GroupByRange. + protected static int GetPercentile(Student s) + { + double avg = s.ExamScores.Average(); + return avg > 0 ? (int)avg / 10 : 0; + } \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-group-query-results_5.cs b/samples/snippets/csharp/concepts/linq/how-to-group-query-results_5.cs new file mode 100644 index 0000000000000..9331531613bf6 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-group-query-results_5.cs @@ -0,0 +1,40 @@ + public void GroupByRange() + { + Console.WriteLine("\r\nGroup by numeric range and project into a new anonymous type:"); + + var queryNumericRange = + from student in students + let percentile = GetPercentile(student) + group new { student.FirstName, student.LastName } by percentile into percentGroup + orderby percentGroup.Key + select percentGroup; + + // Nested foreach required to iterate over groups and group items. + foreach (var studentGroup in queryNumericRange) + { + Console.WriteLine($"Key: {studentGroup.Key * 10}"); + foreach (var item in studentGroup) + { + Console.WriteLine("\t{item.LastName}, {item.FirstName}"); + } + } + } + /* Output: + Group by numeric range and project into a new anonymous type: + Key: 60 + Garcia, Debra + Key: 70 + O'Donnell, Claire + Key: 80 + Adams, Terry + Feng, Hanying + Garcia, Cesar + Garcia, Hugo + Mortensen, Sven + Omelchenko, Svetlana + Tucker, Lance + Zabokritski, Eugene + Key: 90 + Fakhouri, Fadi + Tucker, Michael + */ \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-group-query-results_6.cs b/samples/snippets/csharp/concepts/linq/how-to-group-query-results_6.cs new file mode 100644 index 0000000000000..231b66aebe0f5 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-group-query-results_6.cs @@ -0,0 +1,34 @@ + public void GroupByBoolean() + { + Console.WriteLine("\r\nGroup by a Boolean into two groups with string keys"); + Console.WriteLine("\"True\" and \"False\" and project into a new anonymous type:"); + var queryGroupByAverages = from student in students + group new { student.FirstName, student.LastName } + by student.ExamScores.Average() > 75 into studentGroup + select studentGroup; + + foreach (var studentGroup in queryGroupByAverages) + { + Console.WriteLine($"Key: {studentGroup.Key}"); + foreach (var student in studentGroup) + Console.WriteLine($"\t{student.FirstName} {student.LastName}"); + } + } + /* Output: + Group by a Boolean into two groups with string keys + "True" and "False" and project into a new anonymous type: + Key: True + Terry Adams + Fadi Fakhouri + Hanying Feng + Cesar Garcia + Hugo Garcia + Sven Mortensen + Svetlana Omelchenko + Lance Tucker + Michael Tucker + Eugene Zabokritski + Key: False + Debra Garcia + Claire O'Donnell + */ \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-group-query-results_7.cs b/samples/snippets/csharp/concepts/linq/how-to-group-query-results_7.cs new file mode 100644 index 0000000000000..6cd4b95bed50e --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-group-query-results_7.cs @@ -0,0 +1,46 @@ + public void GroupByCompositeKey() + { + + var queryHighScoreGroups = + from student in students + group student by new { FirstLetter = student.LastName[0], + Score = student.ExamScores[0] > 85 } into studentGroup + orderby studentGroup.Key.FirstLetter + select studentGroup; + + Console.WriteLine("\r\nGroup and order by a compound key:"); + foreach (var scoreGroup in queryHighScoreGroups) + { + string s = scoreGroup.Key.Score == true ? "more than" : "less than"; + ($"Name starts with {scoreGroup.Key.FirstLetter} who scored {s} 85"); + foreach (var item in scoreGroup) + { + Console.WriteLine($"\t{item.FirstName} {item.LastName}"); + } + } + } + /* Output: + Group and order by a compound key: + Name starts with A who scored more than 85 + Terry Adams + Name starts with F who scored more than 85 + Fadi Fakhouri + Hanying Feng + Name starts with G who scored more than 85 + Cesar Garcia + Hugo Garcia + Name starts with G who scored less than 85 + Debra Garcia + Name starts with M who scored more than 85 + Sven Mortensen + Name starts with O who scored less than 85 + Claire O'Donnell + Name starts with O who scored more than 85 + Svetlana Omelchenko + Name starts with T who scored less than 85 + Lance Tucker + Name starts with T who scored more than 85 + Michael Tucker + Name starts with Z who scored more than 85 + Eugene Zabokritski + */ \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-group-results-by-contiguous-keys_1.cs b/samples/snippets/csharp/concepts/linq/how-to-group-results-by-contiguous-keys_1.cs new file mode 100644 index 0000000000000..19603957ef67b --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-group-results-by-contiguous-keys_1.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections.Generic; +using System.Linq; + + +namespace ChunkIt +{ + // Static class to contain the extension methods. + public static class MyExtensions + { + public static IEnumerable> ChunkBy(this IEnumerable source, Func keySelector) + { + return source.ChunkBy(keySelector, EqualityComparer.Default); + } + + public static IEnumerable> ChunkBy(this IEnumerable source, Func keySelector, IEqualityComparer comparer) + { + // Flag to signal end of source sequence. + const bool noMoreSourceElements = true; + + // Auto-generated iterator for the source array. + var enumerator = source.GetEnumerator(); + + // Move to the first element in the source sequence. + if (!enumerator.MoveNext()) yield break; + + // Iterate through source sequence and create a copy of each Chunk. + // On each pass, the iterator advances to the first element of the next "Chunk" + // in the source sequence. This loop corresponds to the outer foreach loop that + // executes the query. + Chunk current = null; + while (true) + { + // Get the key for the current Chunk. The source iterator will churn through + // the source sequence until it finds an element with a key that doesn't match. + var key = keySelector(enumerator.Current); + + // Make a new Chunk (group) object that initially has one GroupItem, which is a copy of the current source element. + current = new Chunk(key, enumerator, value => comparer.Equals(key, keySelector(value))); + + // Return the Chunk. A Chunk is an IGrouping, which is the return value of the ChunkBy method. + // At this point the Chunk only has the first element in its source sequence. The remaining elements will be + // returned only when the client code foreach's over this chunk. See Chunk.GetEnumerator for more info. + yield return current; + + // Check to see whether (a) the chunk has made a copy of all its source elements or + // (b) the iterator has reached the end of the source sequence. If the caller uses an inner + // foreach loop to iterate the chunk items, and that loop ran to completion, + // then the Chunk.GetEnumerator method will already have made + // copies of all chunk items before we get here. If the Chunk.GetEnumerator loop did not + // enumerate all elements in the chunk, we need to do it here to avoid corrupting the iterator + // for clients that may be calling us on a separate thread. + if (current.CopyAllChunkElements() == noMoreSourceElements) + { + yield break; + } + } + } + + // A Chunk is a contiguous group of one or more source elements that have the same key. A Chunk + // has a key and a list of ChunkItem objects, which are copies of the elements in the source sequence. + class Chunk : IGrouping + { + // INVARIANT: DoneCopyingChunk == true || + // (predicate != null && predicate(enumerator.Current) && current.Value == enumerator.Current) + + // A Chunk has a linked list of ChunkItems, which represent the elements in the current chunk. Each ChunkItem + // has a reference to the next ChunkItem in the list. + class ChunkItem + { + public ChunkItem(TSource value) + { + Value = value; + } + public readonly TSource Value; + public ChunkItem Next = null; + } + // The value that is used to determine matching elements + private readonly TKey key; + + // Stores a reference to the enumerator for the source sequence + private IEnumerator enumerator; + + // A reference to the predicate that is used to compare keys. + private Func predicate; + + // Stores the contents of the first source element that + // belongs with this chunk. + private readonly ChunkItem head; + + // End of the list. It is repositioned each time a new + // ChunkItem is added. + private ChunkItem tail; + + // Flag to indicate the source iterator has reached the end of the source sequence. + internal bool isLastSourceElement = false; + + // Private object for thread syncronization + private object m_Lock; + + // REQUIRES: enumerator != null && predicate != null + public Chunk(TKey key, IEnumerator enumerator, Func predicate) + { + this.key = key; + this.enumerator = enumerator; + this.predicate = predicate; + + // A Chunk always contains at least one element. + head = new ChunkItem(enumerator.Current); + + // The end and beginning are the same until the list contains > 1 elements. + tail = head; + + m_Lock = new object(); + } + + // Indicates that all chunk elements have been copied to the list of ChunkItems, + // and the source enumerator is either at the end, or else on an element with a new key. + // the tail of the linked list is set to null in the CopyNextChunkElement method if the + // key of the next element does not match the current chunk's key, or there are no more elements in the source. + private bool DoneCopyingChunk => tail == null; + + // Adds one ChunkItem to the current group + // REQUIRES: !DoneCopyingChunk && lock(this) + private void CopyNextChunkElement() + { + // Try to advance the iterator on the source sequence. + // If MoveNext returns false we are at the end, and isLastSourceElement is set to true + isLastSourceElement = !enumerator.MoveNext(); + + // If we are (a) at the end of the source, or (b) at the end of the current chunk + // then null out the enumerator and predicate for reuse with the next chunk. + if (isLastSourceElement || !predicate(enumerator.Current)) + { + enumerator = null; + predicate = null; + } + else + { + tail.Next = new ChunkItem(enumerator.Current); + } + + // tail will be null if we are at the end of the chunk elements + // This check is made in DoneCopyingChunk. + tail = tail.Next; + } + + // Called after the end of the last chunk was reached. It first checks whether + // there are more elements in the source sequence. If there are, it + // Returns true if enumerator for this chunk was exhausted. + internal bool CopyAllChunkElements() + { + while (true) + { + lock (m_Lock) + { + if (DoneCopyingChunk) + { + // If isLastSourceElement is false, + // it signals to the outer iterator + // to continue iterating. + return isLastSourceElement; + } + else + { + CopyNextChunkElement(); + } + } + } + } + + public TKey Key => key; + + // Invoked by the inner foreach loop. This method stays just one step ahead + // of the client requests. It adds the next element of the chunk only after + // the clients requests the last element in the list so far. + public IEnumerator GetEnumerator() + { + //Specify the initial element to enumerate. + ChunkItem current = head; + + // There should always be at least one ChunkItem in a Chunk. + while (current != null) + { + // Yield the current item in the list. + yield return current.Value; + + // Copy the next item from the source sequence, + // if we are at the end of our local list. + lock (m_Lock) + { + if (current == tail) + { + CopyNextChunkElement(); + } + } + + // Move to the next ChunkItem in the list. + current = current.Next; + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); + { + return GetEnumerator(); + } + } + } + + // A simple named type is used for easier viewing in the debugger. Anonymous types + // work just as well with the ChunkBy operator. + public class KeyValPair + { + public string Key { get; set; } + public string Value { get; set; } + } + + class Program + { + // The source sequence. + public static IEnumerable list; + + // Query variable declared as class member to be available + // on different threads. + static IEnumerable> query; + + + static void Main(string[] args) + { + // Initialize the source sequence with an array initializer. + list = new[] + { + new KeyValPair{ Key = "A", Value = "We" }, + new KeyValPair{ Key = "A", Value = "Think" }, + new KeyValPair{ Key = "A", Value = "That" }, + new KeyValPair{ Key = "B", Value = "Linq" }, + new KeyValPair{ Key = "C", Value = "Is" }, + new KeyValPair{ Key = "A", Value = "Really" }, + new KeyValPair{ Key = "B", Value = "Cool" }, + new KeyValPair{ Key = "B", Value = "!" } + }; + + // Create the query by using our user-defined query operator. + query = list.ChunkBy(p => p.Key); + + + // ChunkBy returns IGrouping objects, therefore a nested + // foreach loop is required to access the elements in each "chunk". + foreach (var item in query) + { + Console.WriteLine("Group key = {0}", item.Key); + foreach (var inner in item) + { + Console.WriteLine($"\t{inner.Value}"); + } + } + + Console.WriteLine("Press any key to exit"); + Console.ReadKey(); + } + + } +} \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-handle-exceptions-in-query-expressions_1.cs b/samples/snippets/csharp/concepts/linq/how-to-handle-exceptions-in-query-expressions_1.cs new file mode 100644 index 0000000000000..655839d5cb371 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-handle-exceptions-in-query-expressions_1.cs @@ -0,0 +1,39 @@ + class ExceptionsOutsideQuery + { + static void Main() + { + // DO THIS with a datasource that might + // throw an exception. It is easier to deal with + // outside of the query expression. + IEnumerable dataSource; + try + { + dataSource = GetData(); + } + catch (InvalidOperationException) + { + // Handle (or don't handle) the exception + // in the way that is appropriate for your application. + Console.WriteLine("Invalid operation"); + goto Exit; + } + + // If we get here, it is safe to proceed. + var query = from i in dataSource + select i * i; + + foreach (var i in query) + Console.WriteLine(i.ToString()); + + //Keep the console window open in debug mode + Exit: + Console.WriteLine("Press any key to exit"); + Console.ReadKey(); + } + + // A data source that is very likely to throw an exception! + static IEnumerable GetData() + { + throw new InvalidOperationException(); + } + } \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-handle-exceptions-in-query-expressions_2.cs b/samples/snippets/csharp/concepts/linq/how-to-handle-exceptions-in-query-expressions_2.cs new file mode 100644 index 0000000000000..98e954d8d13a7 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-handle-exceptions-in-query-expressions_2.cs @@ -0,0 +1,48 @@ + class QueryThatThrows + { + static void Main() + { + // Data source. + string[] files = { "fileA.txt", "fileB.txt", "fileC.txt" }; + + // Demonstration query that throws. + var exceptionDemoQuery = + from file in files + let n = SomeMethodThatMightThrow(file) + select n; + + // Runtime exceptions are thrown when query is executed. + // Therefore they must be handled in the foreach loop. + try + { + foreach (var item in exceptionDemoQuery) + { + Console.WriteLine($"Processing {item}"); + } + } + + // Catch whatever exception you expect to raise + // and/or do any necessary cleanup in a finally block + catch (InvalidOperationException e) + { + Console.WriteLine(e.Message); + } + + //Keep the console window open in debug mode + Console.WriteLine("Press any key to exit"); + Console.ReadKey(); + } + + // Not very useful as a general purpose method. + static string SomeMethodThatMightThrow(string s) + { + if (s[4] == 'C') + throw new InvalidOperationException(); + return @"C:\newFolder\" + s; + } + } + /* Output: + Processing C:\newFolder\fileA.txt + Processing C:\newFolder\fileB.txt + Operation is not valid due to the current state of the object. + */ \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-handle-null-values-in-query-expressions_1.cs b/samples/snippets/csharp/concepts/linq/how-to-handle-null-values-in-query-expressions_1.cs new file mode 100644 index 0000000000000..4032dd78e0fbb --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-handle-null-values-in-query-expressions_1.cs @@ -0,0 +1,6 @@ + var query1 = + from c in categories + where c != null + join p in products on c.ID equals + p?.CategoryID + select new { Category = c.Name, Name = p.Name }; \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-handle-null-values-in-query-expressions_2.cs b/samples/snippets/csharp/concepts/linq/how-to-handle-null-values-in-query-expressions_2.cs new file mode 100644 index 0000000000000..d6fe656b2aad0 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-handle-null-values-in-query-expressions_2.cs @@ -0,0 +1,8 @@ + void TestMethod(Northwind db) + { + var query = + from o in db.Orders + join e in db.Employees + on o.EmployeeID equals (int?)e.EmployeeID + select new { o.OrderID, e.FirstName }; + } \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-order-the-results-of-a-join-clause_1.cs b/samples/snippets/csharp/concepts/linq/how-to-order-the-results-of-a-join-clause_1.cs new file mode 100644 index 0000000000000..1af874490422a --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-order-the-results-of-a-join-clause_1.cs @@ -0,0 +1,88 @@ + class HowToOrderJoins + { + #region Data + class Product + { + public string Name { get; set; } + public int CategoryID { get; set; } + } + + class Category + { + public string Name { get; set; } + public int ID { get; set; } + } + + // Specify the first data source. + List categories = new List() + { + new Category(){Name="Beverages", ID=001}, + new Category(){ Name="Condiments", ID=002}, + new Category(){ Name="Vegetables", ID=003}, + new Category() { Name="Grains", ID=004}, + new Category() { Name="Fruit", ID=005} + }; + + // Specify the second data source. + List products = new List() + { + new Product{Name="Cola", CategoryID=001}, + new Product{Name="Tea", CategoryID=001}, + new Product{Name="Mustard", CategoryID=002}, + new Product{Name="Pickles", CategoryID=002}, + new Product{Name="Carrots", CategoryID=003}, + new Product{Name="Bok Choy", CategoryID=003}, + new Product{Name="Peaches", CategoryID=005}, + new Product{Name="Melons", CategoryID=005}, + }; + #endregion + static void Main() + { + HowToOrderJoins app = new HowToOrderJoins(); + app.OrderJoin1(); + + // Keep console window open in debug mode. + Console.WriteLine("Press any key to exit."); + Console.ReadKey(); + + } + + void OrderJoin1() + { + var groupJoinQuery2 = + from category in categories + join prod in products on category.ID equals prod.CategoryID into prodGroup + orderby category.Name + select new + { + Category = category.Name, + Products = from prod2 in prodGroup + orderby prod2.Name + select prod2 + }; + + foreach (var productGroup in groupJoinQuery2) + { + Console.WriteLine(productGroup.Category); + foreach (var prodItem in productGroup.Products) + { + Console.WriteLine(" {prodItem.Name:-10} {prodItem.CategoryID}"); + } + } + } + /* Output: + Beverages + Cola 1 + Tea 1 + Condiments + Mustard 2 + Pickles 2 + Fruit + Melons 5 + Peaches 5 + Grains + Vegetables + Bok Choy 3 + Carrots 3 + */ + } \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-perform-a-subquery-on-a-grouping-operation_1.cs b/samples/snippets/csharp/concepts/linq/how-to-perform-a-subquery-on-a-grouping-operation_1.cs new file mode 100644 index 0000000000000..94c1b5720efe5 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-perform-a-subquery-on-a-grouping-operation_1.cs @@ -0,0 +1,21 @@ + public void QueryMax() + { + var queryGroupMax = + from student in students + group student by student.Year into studentGroup + select new + { + Level = studentGroup.Key, + HighestScore = + (from student2 in studentGroup + select student2.ExamScores.Average()).Max() + }; + + int count = queryGroupMax.Count(); + Console.WriteLine($"Number of groups = {count}"); + + foreach (var item in queryGroupMax) + { + Console.WriteLine($" {item.Level} Highest Score={item.HighestScore}"); + } + } \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-perform-custom-join-operations_1.cs b/samples/snippets/csharp/concepts/linq/how-to-perform-custom-join-operations_1.cs new file mode 100644 index 0000000000000..9ef8fbf123452 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-perform-custom-join-operations_1.cs @@ -0,0 +1,117 @@ + class CustomJoins + { + + #region Data + + class Product + { + public string Name { get; set; } + public int CategoryID { get; set; } + } + + class Category + { + public string Name { get; set; } + public int ID { get; set; } + } + + // Specify the first data source. + List categories = new List() + { + new Category(){Name="Beverages", ID=001}, + new Category(){ Name="Condiments", ID=002}, + new Category(){ Name="Vegetables", ID=003}, + }; + + // Specify the second data source. + List products = new List() + { + new Product{Name="Tea", CategoryID=001}, + new Product{Name="Mustard", CategoryID=002}, + new Product{Name="Pickles", CategoryID=002}, + new Product{Name="Carrots", CategoryID=003}, + new Product{Name="Bok Choy", CategoryID=003}, + new Product{Name="Peaches", CategoryID=005}, + new Product{Name="Melons", CategoryID=005}, + new Product{Name="Ice Cream", CategoryID=007}, + new Product{Name="Mackerel", CategoryID=012}, + }; + #endregion + + static void Main() + { + CustomJoins app = new CustomJoins(); + app.CrossJoin(); + app.NonEquijoin(); + + Console.WriteLine("Press any key to exit."); + Console.ReadKey(); + } + + void CrossJoin() + { + var crossJoinQuery = + from c in categories + from p in products + select new { c.ID, p.Name }; + + Console.WriteLine("Cross Join Query:"); + foreach (var v in crossJoinQuery) + { + Console.WriteLine($"v.ID:-5}{v.Name}); + } + } + + void NonEquijoin() + { + var nonEquijoinQuery = + from p in products + let catIds = from c in categories + select c.ID + where catIds.Contains(p.CategoryID) == true + select new { Product = p.Name, CategoryID = p.CategoryID }; + + Console.WriteLine("Non-equijoin query:"); + foreach (var v in nonEquijoinQuery) + { + Console.WriteLine($"{v.CategoryID:-5}{v.Product}"); + } + } + } + /* Output: + Cross Join Query: + 1 Tea + 1 Mustard + 1 Pickles + 1 Carrots + 1 Bok Choy + 1 Peaches + 1 Melons + 1 Ice Cream + 1 Mackerel + 2 Tea + 2 Mustard + 2 Pickles + 2 Carrots + 2 Bok Choy + 2 Peaches + 2 Melons + 2 Ice Cream + 2 Mackerel + 3 Tea + 3 Mustard + 3 Pickles + 3 Carrots + 3 Bok Choy + 3 Peaches + 3 Melons + 3 Ice Cream + 3 Mackerel + Non-equijoin query: + 1 Tea + 2 Mustard + 2 Pickles + 3 Carrots + 3 Bok Choy + Press any key to exit. + */ \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-perform-custom-join-operations_2.cs b/samples/snippets/csharp/concepts/linq/how-to-perform-custom-join-operations_2.cs new file mode 100644 index 0000000000000..c331515b1386f --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-perform-custom-join-operations_2.cs @@ -0,0 +1,67 @@ + class MergeTwoCSVFiles + { + static void Main() + { + // See section Compiling the Code for information about the data files. + string[] names = System.IO.File.ReadAllLines(@"../../../names.csv"); + string[] scores = System.IO.File.ReadAllLines(@"../../../scores.csv"); + + // Merge the data sources using a named type. + // You could use var instead of an explicit type for the query. + IEnumerable queryNamesScores = + // Split each line in the data files into an array of strings. + from name in names + let x = name.Split(',') + from score in scores + let s = score.Split(',') + // Look for matching IDs from the two data files. + where x[2] == s[0] + // If the IDs match, build a Student object. + select new Student() + { + FirstName = x[0], + LastName = x[1], + ID = Convert.ToInt32(x[2]), + ExamScores = (from scoreAsText in s.Skip(1) + select Convert.ToInt32(scoreAsText)). + ToList() + }; + + // Optional. Store the newly created student objects in memory + // for faster access in future queries + List students = queryNamesScores.ToList(); + + foreach (var student in students) + { + Console.WriteLine($"The average score of {student.FirstName} {student.LastName} is + {student.ExamScores.Average()}."); + } + + //Keep console window open in debug mode + Console.WriteLine("Press any key to exit."); + Console.ReadKey(); + } + } + + class Student + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int ID { get; set; } + public List ExamScores { get; set; } + } + + /* Output: + The average score of Omelchenko Svetlana is 82.5. + The average score of O'Donnell Claire is 72.25. + The average score of Mortensen Sven is 84.5. + The average score of Garcia Cesar is 88.25. + The average score of Garcia Debra is 67. + The average score of Fakhouri Fadi is 92.25. + The average score of Feng Hanying is 88. + The average score of Garcia Hugo is 85.75. + The average score of Tucker Lance is 81.75. + The average score of Adams Terry is 85.25. + The average score of Zabokritski Eugene is 83. + The average score of Tucker Michael is 92. + */ \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-perform-grouped-joins_1.cs b/samples/snippets/csharp/concepts/linq/how-to-perform-grouped-joins_1.cs new file mode 100644 index 0000000000000..b9acc14b11e2f --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-perform-grouped-joins_1.cs @@ -0,0 +1,60 @@ + class Person + { + public string FirstName { get; set; } + public string LastName { get; set; } + } + + class Pet + { + public string Name { get; set; } + public Person Owner { get; set; } + } + + /// + /// This example performs a grouped join. + /// + public static void GroupJoinExample() + { + Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" }; + Person terry = new Person { FirstName = "Terry", LastName = "Adams" }; + Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" }; + Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" }; + + Pet barley = new Pet { Name = "Barley", Owner = terry }; + Pet boots = new Pet { Name = "Boots", Owner = terry }; + Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry }; + Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + + // Create two lists. + List people = new List { magnus, terry, charlotte, arlene }; + List pets = new List { barley, boots, whiskers, bluemoon, daisy }; + + // Create a list where each element is an anonymous type + // that contains the person's first name and a collection of + // pets that are owned by them. + var query = from person in people + join pet in pets on person equals pet.Owner into gj + select new { OwnerName = person.FirstName, Pets = gj }; + + foreach (var v in query) + { + // Output the owner's name. + Console.WriteLine("{0}:", v.OwnerName); + // Output each of the owner's pet's names. + foreach (Pet pet in v.Pets) + Console.WriteLine(" {0}", pet.Name); + } + } + + // This code produces the following output: + // + // Magnus: + // Daisy + // Terry: + // Barley + // Boots + // Blue Moon + // Charlotte: + // Whiskers + // Arlene: diff --git a/samples/snippets/csharp/concepts/linq/how-to-perform-grouped-joins_2.cs b/samples/snippets/csharp/concepts/linq/how-to-perform-grouped-joins_2.cs new file mode 100644 index 0000000000000..86509be6956b6 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-perform-grouped-joins_2.cs @@ -0,0 +1,62 @@ + + class Person + { + public string FirstName { get; set; } + public string LastName { get; set; } + } + + class Pet + { + public string Name { get; set; } + public Person Owner { get; set; } + } + + /// + /// This example creates XML output from a grouped join. + /// + public static void GroupJoinXMLExample() + { + Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" }; + Person terry = new Person { FirstName = "Terry", LastName = "Adams" }; + Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" }; + Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" }; + + Pet barley = new Pet { Name = "Barley", Owner = terry }; + Pet boots = new Pet { Name = "Boots", Owner = terry }; + Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry }; + Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + + // Create two lists. + List people = new List { magnus, terry, charlotte, arlene }; + List pets = new List { barley, boots, whiskers, bluemoon, daisy }; + + // Create XML to display the hierarchical organization of people and their pets. + XElement ownersAndPets = new XElement("PetOwners", + from person in people + join pet in pets on person equals pet.Owner into gj + select new XElement("Person", + new XAttribute("FirstName", person.FirstName), + new XAttribute("LastName", person.LastName), + from subpet in gj + select new XElement("Pet", subpet.Name))); + + Console.WriteLine(ownersAndPets); + } + + // This code produces the following output: + // + // + // + // Daisy + // + // + // Barley + // Boots + // Blue Moon + // + // + // Whiskers + // + // + // diff --git a/samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_1.cs b/samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_1.cs new file mode 100644 index 0000000000000..962e905d04087 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_1.cs @@ -0,0 +1,52 @@ + class Person + { + public string FirstName { get; set; } + public string LastName { get; set; } + } + + class Pet + { + public string Name { get; set; } + public Person Owner { get; set; } + } + + /// + /// Simple inner join. + /// + public static void InnerJoinExample() + { + Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" }; + Person terry = new Person { FirstName = "Terry", LastName = "Adams" }; + Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" }; + Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" }; + Person rui = new Person { FirstName = "Rui", LastName = "Raposo" }; + + Pet barley = new Pet { Name = "Barley", Owner = terry }; + Pet boots = new Pet { Name = "Boots", Owner = terry }; + Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + Pet bluemoon = new Pet { Name = "Blue Moon", Owner = rui }; + Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + + // Create two lists. + List people = new List { magnus, terry, charlotte, arlene, rui }; + List pets = new List { barley, boots, whiskers, bluemoon, daisy }; + + // Create a collection of person-pet pairs. Each element in the collection + // is an anonymous type containing both the person's name and their pet's name. + var query = from person in people + join pet in pets on person equals pet.Owner + select new { OwnerName = person.FirstName, PetName = pet.Name }; + + foreach (var ownerAndPet in query) + { + Console.WriteLine($"\"{ownerAndPet.PetName}\" is owned by {ownerAndPet.OwnerName}"); + } + } + + // This code produces the following output: + // + // "Daisy" is owned by Magnus + // "Barley" is owned by Terry + // "Boots" is owned by Terry + // "Whiskers" is owned by Charlotte + // "Blue Moon" is owned by Rui diff --git a/samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_2.cs b/samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_2.cs new file mode 100644 index 0000000000000..2e486cb935971 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_2.cs @@ -0,0 +1,50 @@ + class Employee + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int EmployeeID { get; set; } + } + + class Student + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int StudentID { get; set; } + } + + /// + /// Performs a join operation using a composite key. + /// + public static void CompositeKeyJoinExample() + { + // Create a list of employees. + List employees = new List { + new Employee { FirstName = "Terry", LastName = "Adams", EmployeeID = 522459 }, + new Employee { FirstName = "Charlotte", LastName = "Weiss", EmployeeID = 204467 }, + new Employee { FirstName = "Magnus", LastName = "Hedland", EmployeeID = 866200 }, + new Employee { FirstName = "Vernette", LastName = "Price", EmployeeID = 437139 } }; + + // Create a list of students. + List students = new List { + new Student { FirstName = "Vernette", LastName = "Price", StudentID = 9562 }, + new Student { FirstName = "Terry", LastName = "Earls", StudentID = 9870 }, + new Student { FirstName = "Terry", LastName = "Adams", StudentID = 9913 } }; + + // Join the two data sources based on a composite key consisting of first and last name, + // to determine which employees are also students. + IEnumerable query = from employee in employees + join student in students + on new { employee.FirstName, employee.LastName } + equals new { student.FirstName, student.LastName } + select employee.FirstName + " " + employee.LastName; + + Console.WriteLine("The following people are both employees and students:"); + foreach (string name in query) + Console.WriteLine(name); + } + + // This code produces the following output: + // + // The following people are both employees and students: + // Terry Adams + // Vernette Price diff --git a/samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_3.cs b/samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_3.cs new file mode 100644 index 0000000000000..c44c20f9fd77a --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_3.cs @@ -0,0 +1,70 @@ + class Person + { + public string FirstName { get; set; } + public string LastName { get; set; } + } + + class Pet + { + public string Name { get; set; } + public Person Owner { get; set; } + } + + class Cat : Pet + { } + + class Dog : Pet + { } + + public static void MultipleJoinExample() + { + Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" }; + Person terry = new Person { FirstName = "Terry", LastName = "Adams" }; + Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" }; + Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" }; + Person rui = new Person { FirstName = "Rui", LastName = "Raposo" }; + Person phyllis = new Person { FirstName = "Phyllis", LastName = "Harris" }; + + Cat barley = new Cat { Name = "Barley", Owner = terry }; + Cat boots = new Cat { Name = "Boots", Owner = terry }; + Cat whiskers = new Cat { Name = "Whiskers", Owner = charlotte }; + Cat bluemoon = new Cat { Name = "Blue Moon", Owner = rui }; + Cat daisy = new Cat { Name = "Daisy", Owner = magnus }; + + Dog fourwheeldrive = new Dog { Name = "Four Wheel Drive", Owner = phyllis }; + Dog duke = new Dog { Name = "Duke", Owner = magnus }; + Dog denim = new Dog { Name = "Denim", Owner = terry }; + Dog wiley = new Dog { Name = "Wiley", Owner = charlotte }; + Dog snoopy = new Dog { Name = "Snoopy", Owner = rui }; + Dog snickers = new Dog { Name = "Snickers", Owner = arlene }; + + // Create three lists. + List people = + new List { magnus, terry, charlotte, arlene, rui, phyllis }; + List cats = + new List { barley, boots, whiskers, bluemoon, daisy }; + List dogs = + new List { fourwheeldrive, duke, denim, wiley, snoopy, snickers }; + + // The first join matches Person and Cat.Owner from the list of people and + // cats, based on a common Person. The second join matches dogs whose names start + // with the same letter as the cats that have the same owner. + var query = from person in people + join cat in cats on person equals cat.Owner + join dog in dogs on + new { Owner = person, Letter = cat.Name.Substring(0, 1) } + equals new { dog.Owner, Letter = dog.Name.Substring(0, 1) } + select new { CatName = cat.Name, DogName = dog.Name }; + + foreach (var obj in query) + { + Console.WriteLine( + $"The cat \"{obj.CatName}\" shares a house, and the first letter of their name, + with \"{obj.DogName}\"."); + } + } + + // This code produces the following output: + // + // The cat "Daisy" shares a house, and the first letter of their name, with "Duke". + // The cat "Whiskers" shares a house, and the first letter of their name, with "Wiley". diff --git a/samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_4.cs b/samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_4.cs new file mode 100644 index 0000000000000..f21a07bfd9542 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-perform-inner-joins_4.cs @@ -0,0 +1,67 @@ + class Person + { + public string FirstName { get; set; } + public string LastName { get; set; } + } + + class Pet + { + public string Name { get; set; } + public Person Owner { get; set; } + } + + /// + /// Performs an inner join by using GroupJoin(). + /// + public static void InnerGroupJoinExample() + { + Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" }; + Person terry = new Person { FirstName = "Terry", LastName = "Adams" }; + Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" }; + Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" }; + + Pet barley = new Pet { Name = "Barley", Owner = terry }; + Pet boots = new Pet { Name = "Boots", Owner = terry }; + Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry }; + Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + + // Create two lists. + List people = new List { magnus, terry, charlotte, arlene }; + List pets = new List { barley, boots, whiskers, bluemoon, daisy }; + + var query1 = from person in people + join pet in pets on person equals pet.Owner into gj + from subpet in gj + select new { OwnerName = person.FirstName, PetName = subpet.Name }; + + Console.WriteLine("Inner join using GroupJoin():"); + foreach (var v in query1) + { + Console.WriteLine($"{v.OwnerName} - {v.PetName}")); + } + + var query2 = from person in people + join pet in pets on person equals pet.Owner + select new { OwnerName = person.FirstName, PetName = pet.Name }; + + Console.WriteLine("\nThe equivalent operation using Join():"); + foreach (var v in query2) + Console.WriteLine($"{v.OwnerName} - {v.PetName}")); + } + + // This code produces the following output: + // + // Inner join using GroupJoin(): + // Magnus - Daisy + // Terry - Barley + // Terry - Boots + // Terry - Blue Moon + // Charlotte - Whiskers + // + // The equivalent operation using Join(): + // Magnus - Daisy + // Terry - Barley + // Terry - Boots + // Terry - Blue Moon + // Charlotte - Whiskers diff --git a/samples/snippets/csharp/concepts/linq/how-to-perform-left-outer-joins_1.cs b/samples/snippets/csharp/concepts/linq/how-to-perform-left-outer-joins_1.cs new file mode 100644 index 0000000000000..8fb800d21d7ff --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-perform-left-outer-joins_1.cs @@ -0,0 +1,48 @@ + class Person + { + public string FirstName { get; set; } + public string LastName { get; set; } + } + + class Pet + { + public string Name { get; set; } + public Person Owner { get; set; } + } + + public static void LeftOuterJoinExample() + { + Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" }; + Person terry = new Person { FirstName = "Terry", LastName = "Adams" }; + Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" }; + Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" }; + + Pet barley = new Pet { Name = "Barley", Owner = terry }; + Pet boots = new Pet { Name = "Boots", Owner = terry }; + Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry }; + Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + + // Create two lists. + List people = new List { magnus, terry, charlotte, arlene }; + List pets = new List { barley, boots, whiskers, bluemoon, daisy }; + + var query = from person in people + join pet in pets on person equals pet.Owner into gj + from subpet in gj.DefaultIfEmpty() + select new { person.FirstName, PetName = subpet?.Name ?? String.Empty : subpet.Name) }; + + foreach (var v in query) + { + Console.WriteLine($"{v.FirstName:-15}{v.PetName}"); + } + } + + // This code produces the following output: + // + // Magnus: Daisy + // Terry: Barley + // Terry: Boots + // Terry: Blue Moon + // Charlotte: Whiskers + // Arlene: diff --git a/samples/snippets/csharp/concepts/linq/how-to-query-a-collection-of-objects_1.cs b/samples/snippets/csharp/concepts/linq/how-to-query-a-collection-of-objects_1.cs new file mode 100644 index 0000000000000..fd208904d9218 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-query-a-collection-of-objects_1.cs @@ -0,0 +1,88 @@ + public class StudentClass + { + #region data + protected enum GradeLevel { FirstYear = 1, SecondYear, ThirdYear, FourthYear }; + protected class Student + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int ID { get; set; } + public GradeLevel Year; + public List ExamScores; + } + + protected static List students = new List + { + new Student {FirstName = "Terry", LastName = "Adams", ID = 120, + Year = GradeLevel.SecondYear, + ExamScores = new List{ 99, 82, 81, 79}}, + new Student {FirstName = "Fadi", LastName = "Fakhouri", ID = 116, + Year = GradeLevel.ThirdYear, + ExamScores = new List{ 99, 86, 90, 94}}, + new Student {FirstName = "Hanying", LastName = "Feng", ID = 117, + Year = GradeLevel.FirstYear, + ExamScores = new List{ 93, 92, 80, 87}}, + new Student {FirstName = "Cesar", LastName = "Garcia", ID = 114, + Year = GradeLevel.FourthYear, + ExamScores = new List{ 97, 89, 85, 82}}, + new Student {FirstName = "Debra", LastName = "Garcia", ID = 115, + Year = GradeLevel.ThirdYear, + ExamScores = new List{ 35, 72, 91, 70}}, + new Student {FirstName = "Hugo", LastName = "Garcia", ID = 118, + Year = GradeLevel.SecondYear, + ExamScores = new List{ 92, 90, 83, 78}}, + new Student {FirstName = "Sven", LastName = "Mortensen", ID = 113, + Year = GradeLevel.FirstYear, + ExamScores = new List{ 88, 94, 65, 91}}, + new Student {FirstName = "Claire", LastName = "O'Donnell", ID = 112, + Year = GradeLevel.FourthYear, + ExamScores = new List{ 75, 84, 91, 39}}, + new Student {FirstName = "Svetlana", LastName = "Omelchenko", ID = 111, + Year = GradeLevel.SecondYear, + ExamScores = new List{ 97, 92, 81, 60}}, + new Student {FirstName = "Lance", LastName = "Tucker", ID = 119, + Year = GradeLevel.ThirdYear, + ExamScores = new List{ 68, 79, 88, 92}}, + new Student {FirstName = "Michael", LastName = "Tucker", ID = 122, + Year = GradeLevel.FirstYear, + ExamScores = new List{ 94, 92, 91, 91}}, + new Student {FirstName = "Eugene", LastName = "Zabokritski", ID = 121, + Year = GradeLevel.FourthYear, + ExamScores = new List{ 96, 85, 91, 60}} + }; + #endregion + + //Helper method, used in GroupByRange. + protected static int GetPercentile(Student s) + { + double avg = s.ExamScores.Average(); + return avg > 0 ? (int)avg / 10 : 0; + } + + + + public void QueryHighScores(int exam, int score) + { + var highScores = from student in students + where student.ExamScores[exam] > score + select new {Name = student.FirstName, Score = student.ExamScores[exam]}; + + foreach (var item in highScores) + { + Console.WriteLine($"item.Name:-15}{item.Score}}") + } + } + } + + public class Program + { + public static void Main() + { + StudentClass sc = new StudentClass(); + sc.QueryHighScores(1, 90); + + // Keep the console window open in debug mode. + Console.WriteLine("Press any key to exit"); + Console.ReadKey(); + } + } \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-return-a-query-from-a-method_1.cs b/samples/snippets/csharp/concepts/linq/how-to-return-a-query-from-a-method_1.cs new file mode 100644 index 0000000000000..be67b286f318a --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-return-a-query-from-a-method_1.cs @@ -0,0 +1,79 @@ + class MQ + { + // QueryMethhod1 returns a query as its value. + IEnumerable QueryMethod1(ref int[] ints) + { + var intsToStrings = from i in ints + where i > 4 + select i.ToString(); + return intsToStrings; + } + + // QueryMethod2 returns a query as the value of parameter returnQ. + void QueryMethod2(ref int[] ints, out IEnumerable returnQ) + { + var intsToStrings = from i in ints + where i < 4 + select i.ToString(); + returnQ = intsToStrings; + } + + static void Main() + { + MQ app = new MQ(); + + int[] nums = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + // QueryMethod1 returns a query as the value of the method. + var myQuery1 = app.QueryMethod1(ref nums); + + // Query myQuery1 is executed in the following foreach loop. + Console.WriteLine("Results of executing myQuery1:"); + // Rest the mouse pointer over myQuery1 to see its type. + foreach (string s in myQuery1) + { + Console.WriteLine(s); + } + + // You also can execute the query returned from QueryMethod1 + // directly, without using myQuery1. + Console.WriteLine("\nResults of executing myQuery1 directly:"); + // Rest the mouse pointer over the call to QueryMethod1 to see its + // return type. + foreach (string s in app.QueryMethod1(ref nums)) + { + Console.WriteLine(s); + } + + + IEnumerable myQuery2; + // QueryMethod2 returns a query as the value of its out parameter. + app.QueryMethod2(ref nums, out myQuery2); + + // Execute the returned query. + Console.WriteLine("\nResults of executing myQuery2:"); + foreach (string s in myQuery2) + { + Console.WriteLine(s); + } + + + // You can modify a query by using query composition. A saved query + // is nested inside a new query definition that revises the results + // of the first query. + myQuery1 = from item in myQuery1 + orderby item descending + select item; + + // Execute the modified query. + Console.WriteLine("\nResults of executing modified myQuery1:"); + foreach (string s in myQuery1) + { + Console.WriteLine(s); + } + + // Keep console window open in debug mode. + Console.WriteLine("Press any key to exit."); + Console.ReadKey(); + } + } \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-store-the-results-of-a-query-in-memory_1.cs b/samples/snippets/csharp/concepts/linq/how-to-store-the-results-of-a-query-in-memory_1.cs new file mode 100644 index 0000000000000..b6786992ca659 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-store-the-results-of-a-query-in-memory_1.cs @@ -0,0 +1,25 @@ + class StoreQueryResults + { + static List numbers = new List() { 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }; + static void Main() + { + + IEnumerable queryFactorsOfFour = + from num in numbers + where num % 4 == 0 + select num; + + // Store the results in a new variable + // without executing a foreach loop. + List factorsofFourList = queryFactorsOfFour.ToList(); + + // Iterate the list just to prove it holds data. + Console.WriteLine(factorsofFourList[2]); + factorsofFourList[2] = 0; + Console.WriteLine(factorsofFourList[2]); + + // Keep the console window open in debug mode. + Console.WriteLine("Press any key"); + Console.ReadKey(); + } + } \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_1.cs b/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_1.cs new file mode 100644 index 0000000000000..39b333f869891 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_1.cs @@ -0,0 +1,21 @@ + // Query #1. + List numbers = new List() { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; + + // The query variable can also be implicitly typed by using var + IEnumerable filteringQuery = + from num in numbers + where num < 3 || num > 7 + select num; + + // Query #2. + IEnumerable orderingQuery = + from num in numbers + where num < 3 || num > 7 + orderby num ascending + select num; + + // Query #3. + string[] groupingQuery = { "carrots", "cabbage", "broccoli", "beans", "barley" }; + IEnumerable> queryFoodGroups = + from item in groupingQuery + group item by item[0]; \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_2.cs b/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_2.cs new file mode 100644 index 0000000000000..1aed7f53b5463 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_2.cs @@ -0,0 +1,7 @@ + List numbers1 = new List() { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; + List numbers2 = new List() { 15, 14, 11, 13, 19, 18, 16, 17, 12, 10 }; + // Query #4. + double average = numbers1.Average(); + + // Query #5. + IEnumerable concatenationQuery = numbers1.Concat(numbers2); \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_3.cs b/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_3.cs new file mode 100644 index 0000000000000..625b61eadd9cd --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_3.cs @@ -0,0 +1,2 @@ + // Query #6. + IEnumerable largeNumbersQuery = numbers2.Where(c => c > 15); \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_4.cs b/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_4.cs new file mode 100644 index 0000000000000..2342e25f5715a --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_4.cs @@ -0,0 +1,4 @@ + // var is used for convenience in these queries + var average = numbers1.Average(); + var concatenationQuery = numbers1.Concat(numbers2); + var largeNumbersQuery = numbers2.Where(c => c > 15); \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_5.cs b/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_5.cs new file mode 100644 index 0000000000000..48e2c5f38c0f1 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/how-to-write-linq-queries_5.cs @@ -0,0 +1,16 @@ + // Query #7. + + // Using a query expression with method syntax + int numCount1 = + (from num in numbers1 + where num < 3 || num > 7 + select num).Count(); + + // Better: Create a new variable to store + // the method call result + IEnumerable numbersQuery = + from num in numbers1 + where num < 3 || num > 7 + select num; + + int numCount2 = numbersQuery.Count(); \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/index_1.cs b/samples/snippets/csharp/concepts/linq/index_1.cs new file mode 100644 index 0000000000000..d0fa1156a7420 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/index_1.cs @@ -0,0 +1,22 @@ + class LINQQueryExpressions + { + static void Main() + { + + // Specify the data source. + int[] scores = new int[] { 97, 92, 81, 60 }; + + // Define the query expression. + IEnumerable scoreQuery = + from score in scores + where score > 80 + select score; + + // Execute the query. + foreach (int i in scoreQuery) + { + Console.Write(i + " "); + } + } + } + // Output: 97 92 81 \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_1.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_1.cs new file mode 100644 index 0000000000000..fc7c4124c417d --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_1.cs @@ -0,0 +1,5 @@ + IEnumerable highScoresQuery = + from score in scores + where score > 80 + orderby score descending + select score; \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_10.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_10.cs new file mode 100644 index 0000000000000..93ff5404cd46f --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_10.cs @@ -0,0 +1,5 @@ + IEnumerable cityQuery = + from country in countries + from city in country.Cities + where city.Population > 10000 + select city; \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_11.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_11.cs new file mode 100644 index 0000000000000..091aeb4143660 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_11.cs @@ -0,0 +1,3 @@ + var queryCountryGroups = + from country in countries + group country by country.Name[0]; \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_12.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_12.cs new file mode 100644 index 0000000000000..d3529340f2eb5 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_12.cs @@ -0,0 +1,4 @@ + IEnumerable sortedQuery = + from country in countries + orderby country.Area + select country; \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_13.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_13.cs new file mode 100644 index 0000000000000..7d185af9d47c6 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_13.cs @@ -0,0 +1,5 @@ + // Here var is required because the query + // produces an anonymous type. + var queryNameAndPop = + from country in countries + select new { Name = country.Name, Pop = country.Population }; \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_14.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_14.cs new file mode 100644 index 0000000000000..3a85b25a8d0b7 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_14.cs @@ -0,0 +1,16 @@ + // percentileQuery is an IEnumerable> + var percentileQuery = + from country in countries + let percentile = (int) country.Population / 10_000_000 + group country by percentile into countryGroup + where countryGroup.Key >= 20 + orderby countryGroup.Key + select countryGroup; + + // grouping is an IGrouping + foreach (var grouping in percentileQuery) + { + Console.WriteLine(grouping.Key); + foreach (var country in grouping) + Console.WriteLine(country.Name + ":" + country.Population); + } \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_15.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_15.cs new file mode 100644 index 0000000000000..eeb15494caa4f --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_15.cs @@ -0,0 +1,4 @@ + IEnumerable queryCityPop = + from city in cities + where city.Population < 200000 && city.Population > 100000 + select city; \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_16.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_16.cs new file mode 100644 index 0000000000000..c80b74b4c4a77 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_16.cs @@ -0,0 +1,4 @@ + IEnumerable querySortedCountries = + from country in countries + orderby country.Area, country.Population descending + select country; \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_17.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_17.cs new file mode 100644 index 0000000000000..bc120439681dc --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_17.cs @@ -0,0 +1,4 @@ + var categoryQuery = + from cat in categories + join prod in products on cat equals prod.Category + select new { Category = cat, Name = prod.Name }; \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_18.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_18.cs new file mode 100644 index 0000000000000..c3302fbba8dce --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_18.cs @@ -0,0 +1,9 @@ + string[] names = { "Svetlana Omelchenko", "Claire O'Donnell", "Sven Mortensen", "Cesar Garcia" }; + IEnumerable queryFirstNames = + from name in names + let firstName = name.Split(' ')[0] + select firstName; + + foreach (string s in queryFirstNames) + Console.Write(s + " "); + //Output: Svetlana Claire Sven Cesar \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_19.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_19.cs new file mode 100644 index 0000000000000..e25a00c145500 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_19.cs @@ -0,0 +1,11 @@ + var queryGroupMax = + from student in students + group student by student.GradeLevel into studentGroup + select new + { + Level = studentGroup.Key, + HighestScore = + (from student2 in studentGroup + select student2.Scores.Average()) + .Max() + }; \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_2.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_2.cs new file mode 100644 index 0000000000000..d7aabafe06f5e --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_2.cs @@ -0,0 +1,5 @@ + IEnumerable highScoresQuery2 = + from score in scores + where score > 80 + orderby score descending + select String.Format("The score is {0}", score); \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_3.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_3.cs new file mode 100644 index 0000000000000..66472f5c18cec --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_3.cs @@ -0,0 +1,5 @@ + int highScoreCount = + (from score in scores + where score > 80 + select score) + .Count(); \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_4.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_4.cs new file mode 100644 index 0000000000000..9e17c9e721894 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_4.cs @@ -0,0 +1,6 @@ + IEnumerable highScoresQuery3 = + from score in scores + where score > 80 + select score; + + int scoreCount = highScoresQuery3.Count(); \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_5.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_5.cs new file mode 100644 index 0000000000000..4c7f92e62c5fe --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_5.cs @@ -0,0 +1,19 @@ + static void Main() + { + // Data source. + int[] scores = { 90, 71, 82, 93, 75, 82 }; + + // Query Expression. + IEnumerable scoreQuery = //query variable + from score in scores //required + where score > 80 // optional + orderby score descending // optional + select score; //must end with select or group + + // Execute the query to produce the results + foreach (int testScore in scoreQuery) + { + Console.WriteLine(testScore); + } + } + // Outputs: 93 90 82 82 \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_6.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_6.cs new file mode 100644 index 0000000000000..c000c132c72ce --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_6.cs @@ -0,0 +1,9 @@ + //Query syntax + IEnumerable queryMajorCities = + from city in cities + where city.Population > 100000 + select city; + + + // Method-based syntax + IEnumerable queryMajorCities2 = cities.Where(c => c.Population > 100000); \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_7.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_7.cs new file mode 100644 index 0000000000000..e5ab39d3a2633 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_7.cs @@ -0,0 +1,29 @@ + int highestScore = + (from score in scores + select score) + .Max(); + + // or split the expression + IEnumerable scoreQuery = + from score in scores + select score; + + int highScore = scoreQuery.Max(); + // the following returns the same result + int highScore = scores.Max(); + + List largeCitiesList = + (from country in countries + from city in country.Cities + where city.Population > 10000 + select city) + .ToList(); + + // or split the expression + IEnumerable largeCitiesQuery = + from country in countries + from city in country.Cities + where city.Population > 10000 + select city; + + List largeCitiesList2 = largeCitiesQuery.ToList(); \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_8.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_8.cs new file mode 100644 index 0000000000000..f62c8cd4c8b7a --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_8.cs @@ -0,0 +1,7 @@ + // Use of var is optional here and in all queries. + // queryCities is an IEnumerable just as + // when it is explicitly typed. + var queryCities = + from city in cities + where city.Population > 100000 + select city; \ No newline at end of file diff --git a/samples/snippets/csharp/concepts/linq/query-expression-basics_9.cs b/samples/snippets/csharp/concepts/linq/query-expression-basics_9.cs new file mode 100644 index 0000000000000..ce4dce6bd95d9 --- /dev/null +++ b/samples/snippets/csharp/concepts/linq/query-expression-basics_9.cs @@ -0,0 +1,4 @@ + IEnumerable countryAreaQuery = + from country in countries + where country.Area > 500000 //sq km + select country; \ No newline at end of file