From 33cbc1aef974e9d55097148295ea5b15258970ab Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Sep 2025 14:54:12 +0000 Subject: [PATCH 1/8] Initial plan From df1d2cd212a6c4dc5f1e3455f84f403331694f5d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Sep 2025 15:06:49 +0000 Subject: [PATCH 2/8] Replace deprecated type provider with modern in-memory query examples Co-authored-by: BillWagner <493969+BillWagner@users.noreply.github.com> --- .../language-reference/query-expressions.md | 375 +++++++++--------- samples/snippets/fsharp/fssamples.fsproj | 4 +- .../fsharp/query-expressions/basic-query.fs | 79 ++++ .../query-expressions/modern-example.fs | 38 ++ .../query-expressions.fsproj | 20 + .../fsharp/query-expressions/snippet1.fs | 30 ++ .../fsharp/query-expressions/snippet2.fs | 69 ++++ 7 files changed, 432 insertions(+), 183 deletions(-) create mode 100644 samples/snippets/fsharp/query-expressions/basic-query.fs create mode 100644 samples/snippets/fsharp/query-expressions/modern-example.fs create mode 100644 samples/snippets/fsharp/query-expressions/query-expressions.fsproj create mode 100644 samples/snippets/fsharp/query-expressions/snippet1.fs create mode 100644 samples/snippets/fsharp/query-expressions/snippet2.fs diff --git a/docs/fsharp/language-reference/query-expressions.md b/docs/fsharp/language-reference/query-expressions.md index 4fe4f26d42f69..4aafdd2013409 100644 --- a/docs/fsharp/language-reference/query-expressions.md +++ b/docs/fsharp/language-reference/query-expressions.md @@ -15,27 +15,9 @@ query { expression } ## Remarks -Query expressions are a type of computation expression similar to sequence expressions. Just as you specify a sequence by providing code in a sequence expression, you specify a set of data by providing code in a query expression. In a sequence expression, the `yield` keyword identifies data to be returned as part of the resulting sequence. In query expressions, the `select` keyword performs the same function. In addition to the `select` keyword, F# also supports a number of query operators that are much like the parts of a SQL SELECT statement. Here is an example of a simple query expression, along with code that connects to the Northwind OData source. +Query expressions are a type of computation expression similar to sequence expressions. Just as you specify a sequence by providing code in a sequence expression, you specify a set of data by providing code in a query expression. In a sequence expression, the `yield` keyword identifies data to be returned as part of the resulting sequence. In query expressions, the `select` keyword performs the same function. In addition to the `select` keyword, F# also supports a number of query operators that are much like the parts of a SQL SELECT statement. Here is an example of a simple query expression using in-memory data. -```fsharp -// Use the OData type provider to create types that can be used to access the Northwind database. -// Add References to FSharp.Data.TypeProviders and System.Data.Services.Client -open Microsoft.FSharp.Data.TypeProviders - -type Northwind = ODataService<"http://services.odata.org/Northwind/Northwind.svc"> -let db = Northwind.GetDataContext() - -// A query expression. -let query1 = - query { - for customer in db.Customers do - select customer - } - -// Print results -query1 -|> Seq.iter (fun customer -> printfn "Company: %s Contact: %s" customer.CompanyName customer.ContactName) -``` +[!code-fsharp[Main](~/samples/snippets/fsharp/query-expressions/snippet1.fs)] In the previous code example, the query expression is in curly braces. The meaning of the code in the expression is, return every customer in the Customers table in the database in the query results. Query expressions return a type that implements and , and so they can be iterated using the [Seq module](https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-seqmodule.html) as the example shows. @@ -53,22 +35,9 @@ This table assumes a database in the following form: ![Diagram that shows a sample database.](./media/query-expressions/student-course-database.png) -The code in the tables that follow also assumes the following database connection code. Projects should add references to System.Data, System.Data.Linq, and FSharp.Data.TypeProviders assemblies. The code that creates this database is included at the end of this topic. - -```fsharp -open System -open Microsoft.FSharp.Data.TypeProviders -open System.Data.Linq.SqlClient -open System.Linq -open Microsoft.FSharp.Linq - -type schema = SqlDataConnection< @"Data Source=SERVER\INSTANCE;Initial Catalog=MyDatabase;Integrated Security=SSPI;" > - -let db = schema.GetDataContext() +The code in the tables that follow also assumes the following database connection code. Projects should add references to System.Linq. The code that creates this database is included at the end of this topic. -// Needed for some query operator examples: -let data = [ 1; 5; 7; 11; 18; 21] -``` +[!code-fsharp[Main](~/samples/snippets/fsharp/query-expressions/snippet2.fs)] ### Table 1. Query Operators @@ -83,7 +52,7 @@ let data = [ 1; 5; 7; 11; 18; 21] ```fsharp query { - for student in db.Student do + for student in studentsQueryable do select student.Age.Value contains 11 } @@ -97,7 +66,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do select student count } @@ -131,7 +100,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do where (student.StudentID = 1) select student exactlyOne @@ -143,7 +112,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do where (student.StudentID = 1) select student exactlyOneOrDefault @@ -155,7 +124,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do select student headOrDefault } @@ -166,7 +135,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do select student } ``` @@ -176,7 +145,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do where (student.StudentID > 4) select student } @@ -187,7 +156,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do minBy student.StudentID } ``` @@ -197,7 +166,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do maxBy student.StudentID } ``` @@ -207,7 +176,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do groupBy student.Age into g select (g.Key, g.Count()) } @@ -218,7 +187,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do sortBy student.Name select student } @@ -229,7 +198,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do sortByDescending student.Name select student } @@ -240,7 +209,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do where student.Age.HasValue sortBy student.Age.Value thenBy student.Name @@ -253,7 +222,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do where student.Age.HasValue sortBy student.Age.Value thenByDescending student.Name @@ -266,7 +235,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do groupValBy student.Name student.Age into g select (g, g.Key, g.Count()) } @@ -277,7 +246,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do join selection in db.CourseSelection on (student.StudentID = selection.StudentID) select (student, selection) @@ -289,7 +258,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do groupJoin courseSelection in db.CourseSelection on (student.StudentID = courseSelection.StudentID) into g for courseSelection in g do @@ -304,7 +273,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do leftOuterJoin selection in db.CourseSelection on (student.StudentID = selection.StudentID) into result for selection in result.DefaultIfEmpty() do @@ -317,7 +286,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do sumByNullable student.Age } ``` @@ -327,7 +296,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do minByNullable student.Age } ``` @@ -337,7 +306,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do maxByNullable student.Age } ``` @@ -347,7 +316,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do averageByNullable (Nullable.float student.Age) } ``` @@ -357,7 +326,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do averageBy (float student.StudentID) } ``` @@ -367,7 +336,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do join selection in db.CourseSelection on (student.StudentID = selection.StudentID) distinct @@ -379,7 +348,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do where (query { for courseSelection in db.CourseSelection do @@ -393,7 +362,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do find (student.Name = "Abercrombie, Kim") } ``` @@ -403,7 +372,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do all (SqlMethods.Like(student.Name, "%,%")) } ``` @@ -413,7 +382,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do head } ``` @@ -433,7 +402,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do skip 1 } ``` @@ -454,7 +423,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do sumBy student.StudentID } ``` @@ -464,7 +433,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do select student take 2 } @@ -485,7 +454,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do sortByNullable student.Age select student } @@ -496,7 +465,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do sortByNullableDescending student.Age select student } @@ -507,7 +476,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do sortBy student.Name thenByNullable student.Age select student @@ -519,7 +488,7 @@ query { ```fsharp query { - for student in db.Student do + for student in studentsQueryable do sortBy student.Name thenByNullableDescending student.Age select student @@ -552,7 +521,7 @@ SELECT * FROM Student ```fsharp // All students. query { - for student in db.Student do + for student in studentsQueryable do select student } ``` @@ -570,7 +539,7 @@ SELECT COUNT( * ) FROM Student ```fsharp // Count of students. query { - for student in db.Student do + for student in studentsQueryable do count } ``` @@ -597,7 +566,7 @@ WHERE EXISTS ```fsharp // Find students who have signed up at least one course. query { - for student in db.Student do + for student in studentsQueryable do where (query { for courseSelection in db.CourseSelection do @@ -619,13 +588,13 @@ GROUP BY Student.Age ```fsharp // Group by age and count. query { - for n in db.Student do + for n in studentsQueryable do groupBy n.Age into g select (g.Key, g.Count()) } // OR query { - for n in db.Student do + for n in studentsQueryable do groupValBy n.Age n.Age into g select (g.Key, g.Count()) } @@ -646,7 +615,7 @@ HAVING student.Age > 10 ```fsharp // Group students by age where age > 10. query { - for student in db.Student do + for student in studentsQueryable do groupBy student.Age into g where (g.Key.HasValue && g.Key.Value > 10) select (g.Key, g.Count()) @@ -674,7 +643,7 @@ HAVING COUNT( * ) > 1 // Group students by age and count number of students // at each age with more than 1 student. query { - for student in db.Student do + for student in studentsQueryable do groupBy student.Age into group where (group.Count() > 1) select (group.Key, group.Count()) @@ -695,7 +664,7 @@ GROUP BY Student.Age ```fsharp // Group students by age and sum ages. query { - for student in db.Student do + for student in studentsQueryable do groupBy student.Age into g let total = query { @@ -729,7 +698,7 @@ ORDER BY COUNT( * ) DESC // at each age, and display all with count > 1 // in descending order of count. query { - for student in db.Student do + for student in studentsQueryable do groupBy student.Age into g where (g.Count() > 1) sortByDescending (g.Count()) @@ -756,7 +725,7 @@ let idQuery = select id } query { - for student in db.Student do + for student in studentsQueryable do where (idQuery.Contains(student.StudentID)) select student } @@ -776,7 +745,7 @@ WHERE Student.Name LIKE '_e%' ```fsharp // Look for students with Name match _e% pattern and take first two. query { - for student in db.Student do + for student in studentsQueryable do where (SqlMethods.Like( student.Name, "_e%") ) select student take 2 @@ -797,7 +766,7 @@ WHERE Student.Name LIKE '[abc]%' ```fsharp query { - for student in db.Student do + for student in studentsQueryable do where (SqlMethods.Like( student.Name, "[abc]%") ) select student } @@ -818,7 +787,7 @@ WHERE Student.Name LIKE '[^abc]%' ```fsharp // Look for students with name matching [^abc]%% pattern. query { - for student in db.Student do + for student in studentsQueryable do where (SqlMethods.Like( student.Name, "[^abc]%") ) select student } @@ -836,7 +805,7 @@ WHERE Student.Name LIKE '[^abc]%' ```fsharp query { - for n in db.Student do + for n in studentsQueryable do where (SqlMethods.Like( n.Name, "[^abc]%") ) select n.StudentID } @@ -854,7 +823,7 @@ WHERE Student.Name like '%A%' ```fsharp // Using Contains as a query filter. query { - for student in db.Student do + for student in studentsQueryable do where (student.Name.Contains("a")) select student } @@ -874,7 +843,7 @@ ON Student.StudentID = CourseSelection.StudentID ```fsharp // Join Student and CourseSelection tables. query { - for student in db.Student do + for student in studentsQueryable do join selection in db.CourseSelection on (student.StudentID = selection.StudentID) select (student, selection) @@ -894,7 +863,7 @@ ON Student.StudentID = CourseSelection.StudentID ```fsharp //Left Join Student and CourseSelection tables. query { - for student in db.Student do + for student in studentsQueryable do leftOuterJoin selection in db.CourseSelection on (student.StudentID = selection.StudentID) into result for selection in result.DefaultIfEmpty() do @@ -915,7 +884,7 @@ ON Student.StudentID = CourseSelection.StudentID ```fsharp // Join with count. query { - for n in db.Student do + for n in studentsQueryable do join e in db.CourseSelection on (n.StudentID = e.StudentID) count @@ -933,7 +902,7 @@ SELECT DISTINCT StudentID FROM CourseSelection ```fsharp // Join with distinct. query { - for student in db.Student do + for student in studentsQueryable do join selection in db.CourseSelection on (student.StudentID = selection.StudentID) distinct @@ -951,7 +920,7 @@ SELECT DISTINCT COUNT(StudentID) FROM CourseSelection ```fsharp // Join with distinct and count. query { - for n in db.Student do + for n in studentsQueryable do join e in db.CourseSelection on (n.StudentID = e.StudentID) distinct @@ -971,7 +940,7 @@ WHERE Student.Age BETWEEN 10 AND 15 ```fsharp // Selecting students with ages between 10 and 15. query { - for student in db.Student do + for student in studentsQueryable do where (student.Age ?>= 10 && student.Age ?< 15) select student } @@ -989,7 +958,7 @@ WHERE Student.Age = 11 OR Student.Age = 12 ```fsharp // Selecting students with age that's either 11 or 12. query { - for student in db.Student do + for student in studentsQueryable do where (student.Age.Value = 11 || student.Age.Value = 12) select student } @@ -1008,7 +977,7 @@ ORDER BY Student.Age DESC ```fsharp // Selecting students in a certain age range and sorting. query { - for n in db.Student do + for n in studentsQueryable do where (n.Age.Value = 12 || n.Age.Value = 13) sortByNullableDescending n.Age select n @@ -1029,7 +998,7 @@ ORDER BY Student.Name DESC // Selecting students with certain ages, // taking account of the possibility of nulls. query { - for student in db.Student do + for student in studentsQueryable do where ((student.Age.HasValue && student.Age.Value = 11) || (student.Age.HasValue && student.Age.Value = 12)) @@ -1057,7 +1026,7 @@ SELECT * FROM lastStudent ```fsharp let query1 = query { - for n in db.Student do + for n in studentsQueryable do select (n.Name, n.Age) } @@ -1087,7 +1056,7 @@ SELECT * FROM LastStudent ```fsharp let query1 = query { - for n in db.Student do + for n in studentsQueryable do select (n.Name, n.Age) } @@ -1117,7 +1086,7 @@ FROM Student ```fsharp // Using if statement to alter results for special value. query { - for student in db.Student do + for student in studentsQueryable do select (if student.Age.HasValue && student.Age.Value = -1 then (student.StudentID, System.Nullable(100), student.Age) @@ -1143,7 +1112,7 @@ FROM Student ```fsharp // Using if statement to alter results for special values. query { - for student in db.Student do + for student in studentsQueryable do select (if student.Age.HasValue && student.Age.Value = -1 then (student.StudentID, System.Nullable(100), student.Age) @@ -1164,7 +1133,7 @@ SELECT * FROM Student, Course ```fsharp // Multiple table select. query { - for student in db.Student do + for student in studentsQueryable do for course in db.Course do select (student, course) } @@ -1186,7 +1155,7 @@ ON Course.CourseID = CourseSelection.CourseID ```fsharp // Multiple joins. query { - for student in db.Student do + for student in studentsQueryable do join courseSelection in db.CourseSelection on (student.StudentID = courseSelection.StudentID) join course in db.Course @@ -1211,7 +1180,7 @@ ON Course.CourseID = CourseSelection.CourseID ```fsharp // Using leftOuterJoin with multiple joins. query { - for student in db.Student do + for student in studentsQueryable do leftOuterJoin courseSelection in db.CourseSelection on (student.StudentID = courseSelection.StudentID) into g1 for courseSelection in g1.DefaultIfEmpty() do @@ -1350,19 +1319,71 @@ VALUES(15, 7, 3); The following code contains the sample code that appears in this topic. ```fsharp -#if INTERACTIVE -#r "FSharp.Data.TypeProviders.dll" -#r "System.Data.dll" -#r "System.Data.Linq.dll" -#endif open System -open Microsoft.FSharp.Data.TypeProviders -open System.Data.Linq.SqlClient open System.Linq -type schema = SqlDataConnection<"Data Source=SERVER\INSTANCE;Initial Catalog=MyDatabase;Integrated Security=SSPI;"> - -let db = schema.GetDataContext() +// Define simple data types to represent our sample database +type Student = { + StudentID: int + Name: string + Age: int option +} + +type Course = { + CourseID: int + CourseName: string +} + +type CourseSelection = { + ID: int + StudentID: int + CourseID: int +} + +// Sample data +let students = [ + { StudentID = 1; Name = "Abercrombie, Kim"; Age = Some 10 } + { StudentID = 2; Name = "Abolrous, Hazen"; Age = Some 14 } + { StudentID = 3; Name = "Hance, Jim"; Age = Some 12 } + { StudentID = 4; Name = "Adams, Terry"; Age = Some 12 } + { StudentID = 5; Name = "Hansen, Claus"; Age = Some 11 } + { StudentID = 6; Name = "Penor, Lori"; Age = Some 13 } + { StudentID = 7; Name = "Perham, Tom"; Age = Some 12 } + { StudentID = 8; Name = "Peng, Yun-Feng"; Age = None } +] + +let courses = [ + { CourseID = 1; CourseName = "Algebra I" } + { CourseID = 2; CourseName = "Trigonometry" } + { CourseID = 3; CourseName = "Algebra II" } + { CourseID = 4; CourseName = "History" } + { CourseID = 5; CourseName = "English" } + { CourseID = 6; CourseName = "French" } + { CourseID = 7; CourseName = "Chinese" } +] + +let courseSelections = [ + { ID = 1; StudentID = 1; CourseID = 2 } + { ID = 2; StudentID = 1; CourseID = 3 } + { ID = 3; StudentID = 1; CourseID = 5 } + { ID = 4; StudentID = 2; CourseID = 2 } + { ID = 5; StudentID = 2; CourseID = 5 } + { ID = 6; StudentID = 2; CourseID = 6 } + { ID = 7; StudentID = 2; CourseID = 3 } + { ID = 8; StudentID = 3; CourseID = 2 } + { ID = 9; StudentID = 3; CourseID = 1 } + { ID = 10; StudentID = 4; CourseID = 2 } + { ID = 11; StudentID = 4; CourseID = 5 } + { ID = 12; StudentID = 4; CourseID = 2 } + { ID = 13; StudentID = 5; CourseID = 3 } + { ID = 14; StudentID = 5; CourseID = 2 } + { ID = 15; StudentID = 7; CourseID = 3 } +] + +// Convert to queryable collections for LINQ operations +let studentsQueryable = students.AsQueryable() +let coursesQueryable = courses.AsQueryable() +let courseSelectionsQueryable = courseSelections.AsQueryable() let data = [1; 5; 7; 11; 18; 21] @@ -1373,7 +1394,7 @@ type Nullable<'T when 'T : ( new : unit -> 'T) and 'T : struct and 'T :> ValueTy printfn "\ncontains query operator" query { - for student in db.Student do + for student in studentsQueryable do select student.Age.Value contains 11 } @@ -1381,7 +1402,7 @@ query { printfn "\ncount query operator" query { - for student in db.Student do + for student in studentsQueryable do select student count } @@ -1409,7 +1430,7 @@ query { printfn "\nexactlyOne query operator." let student2 = query { - for student in db.Student do + for student in studentsQueryable do where (student.StudentID = 1) select student exactlyOne @@ -1419,7 +1440,7 @@ printfn "Student with StudentID = 1 is %s" student2.Name printfn "\nexactlyOneOrDefault query operator." let student3 = query { - for student in db.Student do + for student in studentsQueryable do where (student.StudentID = 1) select student exactlyOneOrDefault @@ -1429,7 +1450,7 @@ printfn "Student with StudentID = 1 is %s" student3.Name printfn "\nheadOrDefault query operator." let student4 = query { - for student in db.Student do + for student in studentsQueryable do select student headOrDefault } @@ -1437,14 +1458,14 @@ printfn "head student is %s" student4.Name printfn "\nselect query operator." query { - for student in db.Student do + for student in studentsQueryable do select student } |> Seq.iter (fun student -> printfn "StudentID, Name: %d %s" student.StudentID student.Name) printfn "\nwhere query operator." query { - for student in db.Student do + for student in studentsQueryable do where (student.StudentID > 4) select student } @@ -1453,20 +1474,20 @@ query { printfn "\nminBy query operator." let student5 = query { - for student in db.Student do + for student in studentsQueryable do minBy student.StudentID } printfn "\nmaxBy query operator." let student6 = query { - for student in db.Student do + for student in studentsQueryable do maxBy student.StudentID } printfn "\ngroupBy query operator." query { - for student in db.Student do + for student in studentsQueryable do groupBy student.Age into g select (g.Key, g.Count()) } @@ -1474,7 +1495,7 @@ query { printfn "\nsortBy query operator." query { - for student in db.Student do + for student in studentsQueryable do sortBy student.Name select student } @@ -1482,7 +1503,7 @@ query { printfn "\nsortByDescending query operator." query { - for student in db.Student do + for student in studentsQueryable do sortByDescending student.Name select student } @@ -1490,7 +1511,7 @@ query { printfn "\nthenBy query operator." query { - for student in db.Student do + for student in studentsQueryable do where student.Age.HasValue sortBy student.Age.Value thenBy student.Name @@ -1500,7 +1521,7 @@ query { printfn "\nthenByDescending query operator." query { - for student in db.Student do + for student in studentsQueryable do where student.Age.HasValue sortBy student.Age.Value thenByDescending student.Name @@ -1510,7 +1531,7 @@ query { printfn "\ngroupValBy query operator." query { - for student in db.Student do + for student in studentsQueryable do groupValBy student.Name student.Age into g select (g, g.Key, g.Count()) } @@ -1520,56 +1541,56 @@ query { printfn "\n sumByNullable query operator" query { - for student in db.Student do + for student in studentsQueryable do sumByNullable student.Age } |> (fun sum -> printfn "Sum of ages: %s" (sum.Print())) printfn "\n minByNullable" query { - for student in db.Student do + for student in studentsQueryable do minByNullable student.Age } |> (fun age -> printfn "Minimum age: %s" (age.Print())) printfn "\n maxByNullable" query { - for student in db.Student do + for student in studentsQueryable do maxByNullable student.Age } |> (fun age -> printfn "Maximum age: %s" (age.Print())) printfn "\n averageBy" query { - for student in db.Student do + for student in studentsQueryable do averageBy (float student.StudentID) } |> printfn "Average student ID: %f" printfn "\n averageByNullable" query { - for student in db.Student do + for student in studentsQueryable do averageByNullable (Nullable.float student.Age) } |> (fun avg -> printfn "Average age: %s" (avg.Print())) printfn "\n find query operator" query { - for student in db.Student do + for student in studentsQueryable do find (student.Name = "Abercrombie, Kim") } |> (fun student -> printfn "Found a match with StudentID = %d" student.StudentID) printfn "\n all query operator" query { - for student in db.Student do + for student in studentsQueryable do all (SqlMethods.Like(student.Name, "%,%")) } |> printfn "Do all students have a comma in the name? %b" printfn "\n head query operator" query { - for student in db.Student do + for student in studentsQueryable do head } |> (fun student -> printfn "Found the head student with StudentID = %d" student.StudentID) @@ -1583,7 +1604,7 @@ query { printfn "\n skip query operator" query { - for student in db.Student do + for student in studentsQueryable do skip 1 } |> Seq.iter (fun student -> printfn "StudentID = %d" student.StudentID) @@ -1598,14 +1619,14 @@ query { printfn "\n sumBy query operator" query { - for student in db.Student do + for student in studentsQueryable do sumBy student.StudentID } |> printfn "Sum of student IDs: %d" printfn "\n take query operator" query { - for student in db.Student do + for student in studentsQueryable do select student take 2 } @@ -1620,7 +1641,7 @@ query { printfn "\n sortByNullable query operator" query { - for student in db.Student do + for student in studentsQueryable do sortByNullable student.Age select student } @@ -1629,7 +1650,7 @@ query { printfn "\n sortByNullableDescending query operator" query { - for student in db.Student do + for student in studentsQueryable do sortByNullableDescending student.Age select student } @@ -1638,7 +1659,7 @@ query { printfn "\n thenByNullable query operator" query { - for student in db.Student do + for student in studentsQueryable do sortBy student.Name thenByNullable student.Age select student @@ -1648,7 +1669,7 @@ query { printfn "\n thenByNullableDescending query operator" query { - for student in db.Student do + for student in studentsQueryable do sortBy student.Name thenByNullableDescending student.Age select student @@ -1658,21 +1679,21 @@ query { printfn "All students: " query { - for student in db.Student do + for student in studentsQueryable do select student } |> Seq.iter (fun student -> printfn "%s %d %s" student.Name student.StudentID (student.Age.Print())) printfn "\nCount of students: " query { - for student in db.Student do + for student in studentsQueryable do count } |> (fun count -> printfn "Student count: %d" count) printfn "\nExists." query { - for student in db.Student do + for student in studentsQueryable do where (query { for courseSelection in db.CourseSelection do @@ -1683,7 +1704,7 @@ query { printfn "\n Group by age and count" query { - for n in db.Student do + for n in studentsQueryable do groupBy n.Age into g select (g.Key, g.Count()) } @@ -1691,7 +1712,7 @@ query { printfn "\n Group value by age." query { - for n in db.Student do + for n in studentsQueryable do groupValBy n.Age n.Age into g select (g.Key, g.Count()) } @@ -1699,7 +1720,7 @@ query { printfn "\nGroup students by age where age > 10." query { - for student in db.Student do + for student in studentsQueryable do groupBy student.Age into g where (g.Key.HasValue && g.Key.Value > 10) select (g, g.Key) @@ -1711,7 +1732,7 @@ query { printfn "\nGroup students by age and print counts of number of students at each age with more than 1 student." query { - for student in db.Student do + for student in studentsQueryable do groupBy student.Age into group where (group.Count() > 1) select (group.Key, group.Count()) @@ -1721,7 +1742,7 @@ query { printfn "\nGroup students by age and sum ages." query { - for student in db.Student do + for student in studentsQueryable do groupBy student.Age into g let total = query { for student in g do sumByNullable student.Age } select (g.Key, g.Count(), total) @@ -1733,7 +1754,7 @@ query { printfn "\nGroup students by age and count number of students at each age, and display all with count > 1 in descending order of count." query { - for student in db.Student do + for student in studentsQueryable do groupBy student.Age into g where (g.Count() > 1) sortByDescending (g.Count()) @@ -1748,7 +1769,7 @@ let idList = [1; 2; 5; 10] let idQuery = query { for id in idList do select id } query { - for student in db.Student do + for student in studentsQueryable do where (idQuery.Contains(student.StudentID)) select student } @@ -1757,7 +1778,7 @@ query { printfn "\nLook for students with Name match _e%% pattern and take first two." query { - for student in db.Student do + for student in studentsQueryable do where (SqlMethods.Like( student.Name, "_e%") ) select student take 2 @@ -1766,7 +1787,7 @@ query { printfn "\nLook for students with Name matching [abc]%% pattern." query { - for student in db.Student do + for student in studentsQueryable do where (SqlMethods.Like( student.Name, "[abc]%") ) select student } @@ -1774,7 +1795,7 @@ query { printfn "\nLook for students with name matching [^abc]%% pattern." query { - for student in db.Student do + for student in studentsQueryable do where (SqlMethods.Like( student.Name, "[^abc]%") ) select student } @@ -1782,7 +1803,7 @@ query { printfn "\nLook for students with name matching [^abc]%% pattern and select ID." query { - for n in db.Student do + for n in studentsQueryable do where (SqlMethods.Like( n.Name, "[^abc]%") ) select n.StudentID } @@ -1790,7 +1811,7 @@ query { printfn "\n Using Contains as a query filter." query { - for student in db.Student do + for student in studentsQueryable do where (student.Name.Contains("a")) select student } @@ -1799,14 +1820,14 @@ query { printfn "\nSearching for names from a list." let names = [|"a";"b";"c"|] query { - for student in db.Student do + for student in studentsQueryable do if names.Contains (student.Name) then select student } |> Seq.iter (fun student -> printfn "%s" student.Name) printfn "\nJoin Student and CourseSelection tables." query { - for student in db.Student do + for student in studentsQueryable do join selection in db.CourseSelection on (student.StudentID = selection.StudentID) select (student, selection) @@ -1815,7 +1836,7 @@ query { printfn "\nLeft Join Student and CourseSelection tables." query { - for student in db.Student do + for student in studentsQueryable do leftOuterJoin selection in db.CourseSelection on (student.StudentID = selection.StudentID) into result for selection in result.DefaultIfEmpty() do @@ -1830,7 +1851,7 @@ query { printfn "\nJoin with count" query { - for n in db.Student do + for n in studentsQueryable do join e in db.CourseSelection on (n.StudentID = e.StudentID) count @@ -1839,7 +1860,7 @@ query { printfn "\n Join with distinct." query { - for student in db.Student do + for student in studentsQueryable do join selection in db.CourseSelection on (student.StudentID = selection.StudentID) distinct @@ -1848,7 +1869,7 @@ query { printfn "\n Join with distinct and count." query { - for n in db.Student do + for n in studentsQueryable do join e in db.CourseSelection on (n.StudentID = e.StudentID) distinct @@ -1858,7 +1879,7 @@ query { printfn "\n Selecting students with age between 10 and 15." query { - for student in db.Student do + for student in studentsQueryable do where (student.Age.Value >= 10 && student.Age.Value < 15) select student } @@ -1866,7 +1887,7 @@ query { printfn "\n Selecting students with age either 11 or 12." query { - for student in db.Student do + for student in studentsQueryable do where (student.Age.Value = 11 || student.Age.Value = 12) select student } @@ -1874,7 +1895,7 @@ query { printfn "\n Selecting students in a certain age range and sorting." query { - for n in db.Student do + for n in studentsQueryable do where (n.Age.Value = 12 || n.Age.Value = 13) sortByNullableDescending n.Age select n @@ -1883,7 +1904,7 @@ query { printfn "\n Selecting students with certain ages, taking account of possibility of nulls." query { - for student in db.Student do + for student in studentsQueryable do where ((student.Age.HasValue && student.Age.Value = 11) || (student.Age.HasValue && student.Age.Value = 12)) @@ -1896,7 +1917,7 @@ query { printfn "\n Union of two queries." module Queries = let query1 = query { - for n in db.Student do + for n in studentsQueryable do select (n.Name, n.Age) } @@ -1911,7 +1932,7 @@ module Queries = printfn "\n Intersect of two queries." module Queries2 = let query1 = query { - for n in db.Student do + for n in studentsQueryable do select (n.Name, n.Age) } @@ -1925,7 +1946,7 @@ module Queries2 = printfn "\n Using if statement to alter results for special value." query { - for student in db.Student do + for student in studentsQueryable do select (if student.Age.HasValue && student.Age.Value = -1 then (student.StudentID, System.Nullable(100), student.Age) @@ -1935,7 +1956,7 @@ query { printfn "\n Using if statement to alter results special values." query { - for student in db.Student do + for student in studentsQueryable do select (if student.Age.HasValue && student.Age.Value = -1 then (student.StudentID, System.Nullable(100), student.Age) @@ -1947,7 +1968,7 @@ query { printfn "\n Multiple table select." query { - for student in db.Student do + for student in studentsQueryable do for course in db.Course do select (student, course) } @@ -1958,7 +1979,7 @@ query { printfn "\nMultiple Joins" query { - for student in db.Student do + for student in studentsQueryable do join courseSelection in db.CourseSelection on (student.StudentID = courseSelection.StudentID) join course in db.Course @@ -1969,7 +1990,7 @@ query { printfn "\nMultiple Left Outer Joins" query { - for student in db.Student do + for student in studentsQueryable do leftOuterJoin courseSelection in db.CourseSelection on (student.StudentID = courseSelection.StudentID) into g1 for courseSelection in g1.DefaultIfEmpty() do @@ -1984,15 +2005,7 @@ query { And here is the full output when this code is run in F# Interactive. ```console ---> Referenced 'C:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\3.0\Runtime\v4.0\Type Providers\FSharp.Data.TypeProviders.dll' - ---> Referenced 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dll' - ---> Referenced 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.Linq.dll' - contains query operator -Binding session to 'C:\Users\ghogen\AppData\Local\Temp\tmp5E3C.dll'... -Binding session to 'C:\Users\ghogen\AppData\Local\Temp\tmp611A.dll'... Is at least one student age 11? true count query operator diff --git a/samples/snippets/fsharp/fssamples.fsproj b/samples/snippets/fsharp/fssamples.fsproj index d8280b01cbfad..494ca765fec62 100644 --- a/samples/snippets/fsharp/fssamples.fsproj +++ b/samples/snippets/fsharp/fssamples.fsproj @@ -1,8 +1,8 @@ - + Exe - net8.0 + net9.0 preview diff --git a/samples/snippets/fsharp/query-expressions/basic-query.fs b/samples/snippets/fsharp/query-expressions/basic-query.fs new file mode 100644 index 0000000000000..31c36a4c5b448 --- /dev/null +++ b/samples/snippets/fsharp/query-expressions/basic-query.fs @@ -0,0 +1,79 @@ +module QueryExpressions.BasicQuery + +// Basic query expression example using in-memory data +open System +open System.Linq + +// Define simple data types to represent our sample database +type Student = { + StudentID: int + Name: string + Age: int option +} + +type Course = { + CourseID: int + CourseName: string +} + +type CourseSelection = { + ID: int + StudentID: int + CourseID: int +} + +// Sample data +let students = [ + { StudentID = 1; Name = "Abercrombie, Kim"; Age = Some 10 } + { StudentID = 2; Name = "Abolrous, Hazen"; Age = Some 14 } + { StudentID = 3; Name = "Hance, Jim"; Age = Some 12 } + { StudentID = 4; Name = "Adams, Terry"; Age = Some 12 } + { StudentID = 5; Name = "Hansen, Claus"; Age = Some 11 } + { StudentID = 6; Name = "Penor, Lori"; Age = Some 13 } + { StudentID = 7; Name = "Perham, Tom"; Age = Some 12 } + { StudentID = 8; Name = "Peng, Yun-Feng"; Age = None } +] + +let courses = [ + { CourseID = 1; CourseName = "Algebra I" } + { CourseID = 2; CourseName = "Trigonometry" } + { CourseID = 3; CourseName = "Algebra II" } + { CourseID = 4; CourseName = "History" } + { CourseID = 5; CourseName = "English" } + { CourseID = 6; CourseName = "French" } + { CourseID = 7; CourseName = "Chinese" } +] + +let courseSelections = [ + { ID = 1; StudentID = 1; CourseID = 2 } + { ID = 2; StudentID = 1; CourseID = 3 } + { ID = 3; StudentID = 1; CourseID = 5 } + { ID = 4; StudentID = 2; CourseID = 2 } + { ID = 5; StudentID = 2; CourseID = 5 } + { ID = 6; StudentID = 2; CourseID = 6 } + { ID = 7; StudentID = 2; CourseID = 3 } + { ID = 8; StudentID = 3; CourseID = 2 } + { ID = 9; StudentID = 3; CourseID = 1 } + { ID = 10; StudentID = 4; CourseID = 2 } + { ID = 11; StudentID = 4; CourseID = 5 } + { ID = 12; StudentID = 4; CourseID = 2 } + { ID = 13; StudentID = 5; CourseID = 3 } + { ID = 14; StudentID = 5; CourseID = 2 } + { ID = 15; StudentID = 7; CourseID = 3 } +] + +// Convert to queryable collections for LINQ operations +let studentsQueryable = students.AsQueryable() +let coursesQueryable = courses.AsQueryable() +let courseSelectionsQueryable = courseSelections.AsQueryable() + +// A query expression example +let query1 = + query { + for student in studentsQueryable do + select student + } + +// Print results +query1 +|> Seq.iter (fun student -> printfn "Student: %s" student.Name) \ No newline at end of file diff --git a/samples/snippets/fsharp/query-expressions/modern-example.fs b/samples/snippets/fsharp/query-expressions/modern-example.fs new file mode 100644 index 0000000000000..803ad83187c44 --- /dev/null +++ b/samples/snippets/fsharp/query-expressions/modern-example.fs @@ -0,0 +1,38 @@ +module QueryExpressions.ModernExample + +// Modern F# query expression example using in-memory collections +// This provides a working alternative to deprecated type providers + +open System +open System.Linq + +// Simple data structures to demonstrate query capabilities +type Customer = { + CustomerID: int + CompanyName: string + ContactName: string +} + +// Sample data that replaces the external data source +let customers = [ + { CustomerID = 1; CompanyName = "Alfreds Futterkiste"; ContactName = "Maria Anders" } + { CustomerID = 2; CompanyName = "Ana Trujillo Emparedados y helados"; ContactName = "Ana Trujillo" } + { CustomerID = 3; CompanyName = "Antonio Moreno Taquería"; ContactName = "Antonio Moreno" } + { CustomerID = 4; CompanyName = "Around the Horn"; ContactName = "Thomas Hardy" } + { CustomerID = 5; CompanyName = "Berglunds snabbköp"; ContactName = "Christina Berglund" } +] + +// Convert to queryable for LINQ operations +let db = customers.AsQueryable() + +// A query expression that works with modern .NET +let query1 = + query { + for customer in db do + select customer + } + +// Print results (this would be equivalent to the old example) +let printResults() = + query1 + |> Seq.iter (fun customer -> printfn "Company: %s Contact: %s" customer.CompanyName customer.ContactName) \ No newline at end of file diff --git a/samples/snippets/fsharp/query-expressions/query-expressions.fsproj b/samples/snippets/fsharp/query-expressions/query-expressions.fsproj new file mode 100644 index 0000000000000..496947574ce41 --- /dev/null +++ b/samples/snippets/fsharp/query-expressions/query-expressions.fsproj @@ -0,0 +1,20 @@ + + + + Library + net9.0 + preview + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/snippets/fsharp/query-expressions/snippet1.fs b/samples/snippets/fsharp/query-expressions/snippet1.fs new file mode 100644 index 0000000000000..6205d6997f674 --- /dev/null +++ b/samples/snippets/fsharp/query-expressions/snippet1.fs @@ -0,0 +1,30 @@ +// Modern F# query expression example using in-memory data +open System +open System.Linq + +// Simple data structures +type Customer = { + CustomerID: int + CompanyName: string + ContactName: string +} + +// Sample data +let customers = [ + { CustomerID = 1; CompanyName = "Alfreds Futterkiste"; ContactName = "Maria Anders" } + { CustomerID = 2; CompanyName = "Ana Trujillo Emparedados y helados"; ContactName = "Ana Trujillo" } + { CustomerID = 3; CompanyName = "Antonio Moreno Taquería"; ContactName = "Antonio Moreno" } +] + +let db = customers.AsQueryable() + +// A query expression +let query1 = + query { + for customer in db do + select customer + } + +// Print results +query1 +|> Seq.iter (fun customer -> printfn "Company: %s Contact: %s" customer.CompanyName customer.ContactName) \ No newline at end of file diff --git a/samples/snippets/fsharp/query-expressions/snippet2.fs b/samples/snippets/fsharp/query-expressions/snippet2.fs new file mode 100644 index 0000000000000..aaa3c1f51c706 --- /dev/null +++ b/samples/snippets/fsharp/query-expressions/snippet2.fs @@ -0,0 +1,69 @@ +// Database setup example for query expressions +open System +open System.Linq + +// Define simple data types to represent our sample database +type Student = { + StudentID: int + Name: string + Age: int option +} + +type Course = { + CourseID: int + CourseName: string +} + +type CourseSelection = { + ID: int + StudentID: int + CourseID: int +} + +// Sample data +let students = [ + { StudentID = 1; Name = "Abercrombie, Kim"; Age = Some 10 } + { StudentID = 2; Name = "Abolrous, Hazen"; Age = Some 14 } + { StudentID = 3; Name = "Hance, Jim"; Age = Some 12 } + { StudentID = 4; Name = "Adams, Terry"; Age = Some 12 } + { StudentID = 5; Name = "Hansen, Claus"; Age = Some 11 } + { StudentID = 6; Name = "Penor, Lori"; Age = Some 13 } + { StudentID = 7; Name = "Perham, Tom"; Age = Some 12 } + { StudentID = 8; Name = "Peng, Yun-Feng"; Age = None } +] + +let courses = [ + { CourseID = 1; CourseName = "Algebra I" } + { CourseID = 2; CourseName = "Trigonometry" } + { CourseID = 3; CourseName = "Algebra II" } + { CourseID = 4; CourseName = "History" } + { CourseID = 5; CourseName = "English" } + { CourseID = 6; CourseName = "French" } + { CourseID = 7; CourseName = "Chinese" } +] + +let courseSelections = [ + { ID = 1; StudentID = 1; CourseID = 2 } + { ID = 2; StudentID = 1; CourseID = 3 } + { ID = 3; StudentID = 1; CourseID = 5 } + { ID = 4; StudentID = 2; CourseID = 2 } + { ID = 5; StudentID = 2; CourseID = 5 } + { ID = 6; StudentID = 2; CourseID = 6 } + { ID = 7; StudentID = 2; CourseID = 3 } + { ID = 8; StudentID = 3; CourseID = 2 } + { ID = 9; StudentID = 3; CourseID = 1 } + { ID = 10; StudentID = 4; CourseID = 2 } + { ID = 11; StudentID = 4; CourseID = 5 } + { ID = 12; StudentID = 4; CourseID = 2 } + { ID = 13; StudentID = 5; CourseID = 3 } + { ID = 14; StudentID = 5; CourseID = 2 } + { ID = 15; StudentID = 7; CourseID = 3 } +] + +// Convert to queryable collections for LINQ operations +let studentsQueryable = students.AsQueryable() +let coursesQueryable = courses.AsQueryable() +let courseSelectionsQueryable = courseSelections.AsQueryable() + +// Needed for some query operator examples: +let data = [ 1; 5; 7; 11; 18; 21] \ No newline at end of file From dd6ec8497c52a6588e4b8f301cf4df7b574ca45c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Sep 2025 15:12:22 +0000 Subject: [PATCH 3/8] Final fixes: handle optional Age field properly and add AI usage disclosure Co-authored-by: BillWagner <493969+BillWagner@users.noreply.github.com> --- docs/fsharp/language-reference/query-expressions.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/fsharp/language-reference/query-expressions.md b/docs/fsharp/language-reference/query-expressions.md index 4aafdd2013409..b4eb1df9f2a9e 100644 --- a/docs/fsharp/language-reference/query-expressions.md +++ b/docs/fsharp/language-reference/query-expressions.md @@ -1,7 +1,8 @@ --- title: Query Expressions description: Learn about query expression support for LINQ in the F# programming language. -ms.date: 08/15/2020 +ms.date: 09/25/2024 +ai-usage: ai-assisted --- # Query expressions @@ -53,6 +54,7 @@ The code in the tables that follow also assumes the following database connectio ```fsharp query { for student in studentsQueryable do + where student.Age.IsSome select student.Age.Value contains 11 } @@ -211,7 +213,7 @@ query { query { for student in studentsQueryable do where student.Age.HasValue - sortBy student.Age.Value + sortByNullable student.Age thenBy student.Name select student } @@ -224,7 +226,7 @@ query { query { for student in studentsQueryable do where student.Age.HasValue - sortBy student.Age.Value + sortByNullable student.Age thenByDescending student.Name select student } From 9627b658161a96ce3b0bec2c29d90b495f94230b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Sep 2025 15:13:13 +0000 Subject: [PATCH 4/8] Remove redundant query-expressions.fsproj and integrate files into parent project Co-authored-by: BillWagner <493969+BillWagner@users.noreply.github.com> --- samples/snippets/fsharp/fssamples.fsproj | 8 ++++++++ .../query-expressions.fsproj | 20 ------------------- 2 files changed, 8 insertions(+), 20 deletions(-) delete mode 100644 samples/snippets/fsharp/query-expressions/query-expressions.fsproj diff --git a/samples/snippets/fsharp/fssamples.fsproj b/samples/snippets/fsharp/fssamples.fsproj index 494ca765fec62..f5c21532184e3 100644 --- a/samples/snippets/fsharp/fssamples.fsproj +++ b/samples/snippets/fsharp/fssamples.fsproj @@ -8,6 +8,14 @@ + + + + + + + + diff --git a/samples/snippets/fsharp/query-expressions/query-expressions.fsproj b/samples/snippets/fsharp/query-expressions/query-expressions.fsproj deleted file mode 100644 index 496947574ce41..0000000000000 --- a/samples/snippets/fsharp/query-expressions/query-expressions.fsproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - Library - net9.0 - preview - - - - - - - - - - - - - - \ No newline at end of file From 86ffd119e71099dd7212d27e5bec4f14eb8420c7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Sep 2025 18:34:14 +0000 Subject: [PATCH 5/8] Fix date and use ::: syntax for code snippets as requested Co-authored-by: BillWagner <493969+BillWagner@users.noreply.github.com> --- docs/fsharp/language-reference/query-expressions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/fsharp/language-reference/query-expressions.md b/docs/fsharp/language-reference/query-expressions.md index b4eb1df9f2a9e..d9e8a3f28da1c 100644 --- a/docs/fsharp/language-reference/query-expressions.md +++ b/docs/fsharp/language-reference/query-expressions.md @@ -1,7 +1,7 @@ --- title: Query Expressions description: Learn about query expression support for LINQ in the F# programming language. -ms.date: 09/25/2024 +ms.date: 09/26/2024 ai-usage: ai-assisted --- # Query expressions @@ -18,7 +18,7 @@ query { expression } Query expressions are a type of computation expression similar to sequence expressions. Just as you specify a sequence by providing code in a sequence expression, you specify a set of data by providing code in a query expression. In a sequence expression, the `yield` keyword identifies data to be returned as part of the resulting sequence. In query expressions, the `select` keyword performs the same function. In addition to the `select` keyword, F# also supports a number of query operators that are much like the parts of a SQL SELECT statement. Here is an example of a simple query expression using in-memory data. -[!code-fsharp[Main](~/samples/snippets/fsharp/query-expressions/snippet1.fs)] +:::code language="fsharp" source="~/samples/snippets/fsharp/query-expressions/snippet1.fs"::: In the previous code example, the query expression is in curly braces. The meaning of the code in the expression is, return every customer in the Customers table in the database in the query results. Query expressions return a type that implements and , and so they can be iterated using the [Seq module](https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-seqmodule.html) as the example shows. @@ -38,7 +38,7 @@ This table assumes a database in the following form: The code in the tables that follow also assumes the following database connection code. Projects should add references to System.Linq. The code that creates this database is included at the end of this topic. -[!code-fsharp[Main](~/samples/snippets/fsharp/query-expressions/snippet2.fs)] +:::code language="fsharp" source="~/samples/snippets/fsharp/query-expressions/snippet2.fs"::: ### Table 1. Query Operators From ca34877c1eb9e00da4e826d53521ffdcb53b0ae4 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 26 Sep 2025 14:47:36 -0400 Subject: [PATCH 6/8] Update docs/fsharp/language-reference/query-expressions.md --- docs/fsharp/language-reference/query-expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fsharp/language-reference/query-expressions.md b/docs/fsharp/language-reference/query-expressions.md index d9e8a3f28da1c..f67ac3cfd3007 100644 --- a/docs/fsharp/language-reference/query-expressions.md +++ b/docs/fsharp/language-reference/query-expressions.md @@ -1,7 +1,7 @@ --- title: Query Expressions description: Learn about query expression support for LINQ in the F# programming language. -ms.date: 09/26/2024 +ms.date: 09/26/2025 ai-usage: ai-assisted --- # Query expressions From 6ad8a823face8843d53c2dafc699fd827cf7e660 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Oct 2025 06:40:09 +0000 Subject: [PATCH 7/8] Revert db.Student renaming and fix date to 2025 as requested Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- .../language-reference/query-expressions.md | 258 +++++++++--------- .../fsharp/query-expressions/snippet2.fs | 11 +- 2 files changed, 136 insertions(+), 133 deletions(-) diff --git a/docs/fsharp/language-reference/query-expressions.md b/docs/fsharp/language-reference/query-expressions.md index f67ac3cfd3007..dc7a245914a19 100644 --- a/docs/fsharp/language-reference/query-expressions.md +++ b/docs/fsharp/language-reference/query-expressions.md @@ -53,7 +53,7 @@ The code in the tables that follow also assumes the following database connectio ```fsharp query { - for student in studentsQueryable do + for student in db.Student do where student.Age.IsSome select student.Age.Value contains 11 @@ -68,7 +68,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do select student count } @@ -102,7 +102,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do where (student.StudentID = 1) select student exactlyOne @@ -114,7 +114,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do where (student.StudentID = 1) select student exactlyOneOrDefault @@ -126,7 +126,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do select student headOrDefault } @@ -137,7 +137,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do select student } ``` @@ -147,7 +147,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do where (student.StudentID > 4) select student } @@ -158,7 +158,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do minBy student.StudentID } ``` @@ -168,7 +168,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do maxBy student.StudentID } ``` @@ -178,7 +178,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do groupBy student.Age into g select (g.Key, g.Count()) } @@ -189,7 +189,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do sortBy student.Name select student } @@ -200,7 +200,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do sortByDescending student.Name select student } @@ -211,7 +211,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do where student.Age.HasValue sortByNullable student.Age thenBy student.Name @@ -224,7 +224,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do where student.Age.HasValue sortByNullable student.Age thenByDescending student.Name @@ -237,7 +237,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do groupValBy student.Name student.Age into g select (g, g.Key, g.Count()) } @@ -248,7 +248,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do join selection in db.CourseSelection on (student.StudentID = selection.StudentID) select (student, selection) @@ -260,7 +260,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do groupJoin courseSelection in db.CourseSelection on (student.StudentID = courseSelection.StudentID) into g for courseSelection in g do @@ -275,7 +275,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do leftOuterJoin selection in db.CourseSelection on (student.StudentID = selection.StudentID) into result for selection in result.DefaultIfEmpty() do @@ -288,7 +288,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do sumByNullable student.Age } ``` @@ -298,7 +298,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do minByNullable student.Age } ``` @@ -308,7 +308,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do maxByNullable student.Age } ``` @@ -318,7 +318,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do averageByNullable (Nullable.float student.Age) } ``` @@ -328,7 +328,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do averageBy (float student.StudentID) } ``` @@ -338,7 +338,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do join selection in db.CourseSelection on (student.StudentID = selection.StudentID) distinct @@ -350,7 +350,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do where (query { for courseSelection in db.CourseSelection do @@ -364,7 +364,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do find (student.Name = "Abercrombie, Kim") } ``` @@ -374,7 +374,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do all (SqlMethods.Like(student.Name, "%,%")) } ``` @@ -384,7 +384,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do head } ``` @@ -404,7 +404,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do skip 1 } ``` @@ -425,7 +425,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do sumBy student.StudentID } ``` @@ -435,7 +435,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do select student take 2 } @@ -456,7 +456,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do sortByNullable student.Age select student } @@ -467,7 +467,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do sortByNullableDescending student.Age select student } @@ -478,7 +478,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do sortBy student.Name thenByNullable student.Age select student @@ -490,7 +490,7 @@ query { ```fsharp query { - for student in studentsQueryable do + for student in db.Student do sortBy student.Name thenByNullableDescending student.Age select student @@ -523,7 +523,7 @@ SELECT * FROM Student ```fsharp // All students. query { - for student in studentsQueryable do + for student in db.Student do select student } ``` @@ -541,7 +541,7 @@ SELECT COUNT( * ) FROM Student ```fsharp // Count of students. query { - for student in studentsQueryable do + for student in db.Student do count } ``` @@ -568,7 +568,7 @@ WHERE EXISTS ```fsharp // Find students who have signed up at least one course. query { - for student in studentsQueryable do + for student in db.Student do where (query { for courseSelection in db.CourseSelection do @@ -590,13 +590,13 @@ GROUP BY Student.Age ```fsharp // Group by age and count. query { - for n in studentsQueryable do + for n in db.Student do groupBy n.Age into g select (g.Key, g.Count()) } // OR query { - for n in studentsQueryable do + for n in db.Student do groupValBy n.Age n.Age into g select (g.Key, g.Count()) } @@ -617,7 +617,7 @@ HAVING student.Age > 10 ```fsharp // Group students by age where age > 10. query { - for student in studentsQueryable do + for student in db.Student do groupBy student.Age into g where (g.Key.HasValue && g.Key.Value > 10) select (g.Key, g.Count()) @@ -645,7 +645,7 @@ HAVING COUNT( * ) > 1 // Group students by age and count number of students // at each age with more than 1 student. query { - for student in studentsQueryable do + for student in db.Student do groupBy student.Age into group where (group.Count() > 1) select (group.Key, group.Count()) @@ -666,7 +666,7 @@ GROUP BY Student.Age ```fsharp // Group students by age and sum ages. query { - for student in studentsQueryable do + for student in db.Student do groupBy student.Age into g let total = query { @@ -700,7 +700,7 @@ ORDER BY COUNT( * ) DESC // at each age, and display all with count > 1 // in descending order of count. query { - for student in studentsQueryable do + for student in db.Student do groupBy student.Age into g where (g.Count() > 1) sortByDescending (g.Count()) @@ -727,7 +727,7 @@ let idQuery = select id } query { - for student in studentsQueryable do + for student in db.Student do where (idQuery.Contains(student.StudentID)) select student } @@ -747,7 +747,7 @@ WHERE Student.Name LIKE '_e%' ```fsharp // Look for students with Name match _e% pattern and take first two. query { - for student in studentsQueryable do + for student in db.Student do where (SqlMethods.Like( student.Name, "_e%") ) select student take 2 @@ -768,7 +768,7 @@ WHERE Student.Name LIKE '[abc]%' ```fsharp query { - for student in studentsQueryable do + for student in db.Student do where (SqlMethods.Like( student.Name, "[abc]%") ) select student } @@ -789,7 +789,7 @@ WHERE Student.Name LIKE '[^abc]%' ```fsharp // Look for students with name matching [^abc]%% pattern. query { - for student in studentsQueryable do + for student in db.Student do where (SqlMethods.Like( student.Name, "[^abc]%") ) select student } @@ -807,7 +807,7 @@ WHERE Student.Name LIKE '[^abc]%' ```fsharp query { - for n in studentsQueryable do + for n in db.Student do where (SqlMethods.Like( n.Name, "[^abc]%") ) select n.StudentID } @@ -825,7 +825,7 @@ WHERE Student.Name like '%A%' ```fsharp // Using Contains as a query filter. query { - for student in studentsQueryable do + for student in db.Student do where (student.Name.Contains("a")) select student } @@ -845,7 +845,7 @@ ON Student.StudentID = CourseSelection.StudentID ```fsharp // Join Student and CourseSelection tables. query { - for student in studentsQueryable do + for student in db.Student do join selection in db.CourseSelection on (student.StudentID = selection.StudentID) select (student, selection) @@ -865,7 +865,7 @@ ON Student.StudentID = CourseSelection.StudentID ```fsharp //Left Join Student and CourseSelection tables. query { - for student in studentsQueryable do + for student in db.Student do leftOuterJoin selection in db.CourseSelection on (student.StudentID = selection.StudentID) into result for selection in result.DefaultIfEmpty() do @@ -886,7 +886,7 @@ ON Student.StudentID = CourseSelection.StudentID ```fsharp // Join with count. query { - for n in studentsQueryable do + for n in db.Student do join e in db.CourseSelection on (n.StudentID = e.StudentID) count @@ -904,7 +904,7 @@ SELECT DISTINCT StudentID FROM CourseSelection ```fsharp // Join with distinct. query { - for student in studentsQueryable do + for student in db.Student do join selection in db.CourseSelection on (student.StudentID = selection.StudentID) distinct @@ -922,7 +922,7 @@ SELECT DISTINCT COUNT(StudentID) FROM CourseSelection ```fsharp // Join with distinct and count. query { - for n in studentsQueryable do + for n in db.Student do join e in db.CourseSelection on (n.StudentID = e.StudentID) distinct @@ -942,7 +942,7 @@ WHERE Student.Age BETWEEN 10 AND 15 ```fsharp // Selecting students with ages between 10 and 15. query { - for student in studentsQueryable do + for student in db.Student do where (student.Age ?>= 10 && student.Age ?< 15) select student } @@ -960,7 +960,7 @@ WHERE Student.Age = 11 OR Student.Age = 12 ```fsharp // Selecting students with age that's either 11 or 12. query { - for student in studentsQueryable do + for student in db.Student do where (student.Age.Value = 11 || student.Age.Value = 12) select student } @@ -979,7 +979,7 @@ ORDER BY Student.Age DESC ```fsharp // Selecting students in a certain age range and sorting. query { - for n in studentsQueryable do + for n in db.Student do where (n.Age.Value = 12 || n.Age.Value = 13) sortByNullableDescending n.Age select n @@ -1000,7 +1000,7 @@ ORDER BY Student.Name DESC // Selecting students with certain ages, // taking account of the possibility of nulls. query { - for student in studentsQueryable do + for student in db.Student do where ((student.Age.HasValue && student.Age.Value = 11) || (student.Age.HasValue && student.Age.Value = 12)) @@ -1028,7 +1028,7 @@ SELECT * FROM lastStudent ```fsharp let query1 = query { - for n in studentsQueryable do + for n in db.Student do select (n.Name, n.Age) } @@ -1058,7 +1058,7 @@ SELECT * FROM LastStudent ```fsharp let query1 = query { - for n in studentsQueryable do + for n in db.Student do select (n.Name, n.Age) } @@ -1088,7 +1088,7 @@ FROM Student ```fsharp // Using if statement to alter results for special value. query { - for student in studentsQueryable do + for student in db.Student do select (if student.Age.HasValue && student.Age.Value = -1 then (student.StudentID, System.Nullable(100), student.Age) @@ -1114,7 +1114,7 @@ FROM Student ```fsharp // Using if statement to alter results for special values. query { - for student in studentsQueryable do + for student in db.Student do select (if student.Age.HasValue && student.Age.Value = -1 then (student.StudentID, System.Nullable(100), student.Age) @@ -1135,7 +1135,7 @@ SELECT * FROM Student, Course ```fsharp // Multiple table select. query { - for student in studentsQueryable do + for student in db.Student do for course in db.Course do select (student, course) } @@ -1157,7 +1157,7 @@ ON Course.CourseID = CourseSelection.CourseID ```fsharp // Multiple joins. query { - for student in studentsQueryable do + for student in db.Student do join courseSelection in db.CourseSelection on (student.StudentID = courseSelection.StudentID) join course in db.Course @@ -1182,7 +1182,7 @@ ON Course.CourseID = CourseSelection.CourseID ```fsharp // Using leftOuterJoin with multiple joins. query { - for student in studentsQueryable do + for student in db.Student do leftOuterJoin courseSelection in db.CourseSelection on (student.StudentID = courseSelection.StudentID) into g1 for courseSelection in g1.DefaultIfEmpty() do @@ -1383,7 +1383,7 @@ let courseSelections = [ ] // Convert to queryable collections for LINQ operations -let studentsQueryable = students.AsQueryable() +let db.Student = students.AsQueryable() let coursesQueryable = courses.AsQueryable() let courseSelectionsQueryable = courseSelections.AsQueryable() @@ -1396,7 +1396,7 @@ type Nullable<'T when 'T : ( new : unit -> 'T) and 'T : struct and 'T :> ValueTy printfn "\ncontains query operator" query { - for student in studentsQueryable do + for student in db.Student do select student.Age.Value contains 11 } @@ -1404,7 +1404,7 @@ query { printfn "\ncount query operator" query { - for student in studentsQueryable do + for student in db.Student do select student count } @@ -1432,7 +1432,7 @@ query { printfn "\nexactlyOne query operator." let student2 = query { - for student in studentsQueryable do + for student in db.Student do where (student.StudentID = 1) select student exactlyOne @@ -1442,7 +1442,7 @@ printfn "Student with StudentID = 1 is %s" student2.Name printfn "\nexactlyOneOrDefault query operator." let student3 = query { - for student in studentsQueryable do + for student in db.Student do where (student.StudentID = 1) select student exactlyOneOrDefault @@ -1452,7 +1452,7 @@ printfn "Student with StudentID = 1 is %s" student3.Name printfn "\nheadOrDefault query operator." let student4 = query { - for student in studentsQueryable do + for student in db.Student do select student headOrDefault } @@ -1460,14 +1460,14 @@ printfn "head student is %s" student4.Name printfn "\nselect query operator." query { - for student in studentsQueryable do + for student in db.Student do select student } |> Seq.iter (fun student -> printfn "StudentID, Name: %d %s" student.StudentID student.Name) printfn "\nwhere query operator." query { - for student in studentsQueryable do + for student in db.Student do where (student.StudentID > 4) select student } @@ -1476,20 +1476,20 @@ query { printfn "\nminBy query operator." let student5 = query { - for student in studentsQueryable do + for student in db.Student do minBy student.StudentID } printfn "\nmaxBy query operator." let student6 = query { - for student in studentsQueryable do + for student in db.Student do maxBy student.StudentID } printfn "\ngroupBy query operator." query { - for student in studentsQueryable do + for student in db.Student do groupBy student.Age into g select (g.Key, g.Count()) } @@ -1497,7 +1497,7 @@ query { printfn "\nsortBy query operator." query { - for student in studentsQueryable do + for student in db.Student do sortBy student.Name select student } @@ -1505,7 +1505,7 @@ query { printfn "\nsortByDescending query operator." query { - for student in studentsQueryable do + for student in db.Student do sortByDescending student.Name select student } @@ -1513,7 +1513,7 @@ query { printfn "\nthenBy query operator." query { - for student in studentsQueryable do + for student in db.Student do where student.Age.HasValue sortBy student.Age.Value thenBy student.Name @@ -1523,7 +1523,7 @@ query { printfn "\nthenByDescending query operator." query { - for student in studentsQueryable do + for student in db.Student do where student.Age.HasValue sortBy student.Age.Value thenByDescending student.Name @@ -1533,7 +1533,7 @@ query { printfn "\ngroupValBy query operator." query { - for student in studentsQueryable do + for student in db.Student do groupValBy student.Name student.Age into g select (g, g.Key, g.Count()) } @@ -1543,56 +1543,56 @@ query { printfn "\n sumByNullable query operator" query { - for student in studentsQueryable do + for student in db.Student do sumByNullable student.Age } |> (fun sum -> printfn "Sum of ages: %s" (sum.Print())) printfn "\n minByNullable" query { - for student in studentsQueryable do + for student in db.Student do minByNullable student.Age } |> (fun age -> printfn "Minimum age: %s" (age.Print())) printfn "\n maxByNullable" query { - for student in studentsQueryable do + for student in db.Student do maxByNullable student.Age } |> (fun age -> printfn "Maximum age: %s" (age.Print())) printfn "\n averageBy" query { - for student in studentsQueryable do + for student in db.Student do averageBy (float student.StudentID) } |> printfn "Average student ID: %f" printfn "\n averageByNullable" query { - for student in studentsQueryable do + for student in db.Student do averageByNullable (Nullable.float student.Age) } |> (fun avg -> printfn "Average age: %s" (avg.Print())) printfn "\n find query operator" query { - for student in studentsQueryable do + for student in db.Student do find (student.Name = "Abercrombie, Kim") } |> (fun student -> printfn "Found a match with StudentID = %d" student.StudentID) printfn "\n all query operator" query { - for student in studentsQueryable do + for student in db.Student do all (SqlMethods.Like(student.Name, "%,%")) } |> printfn "Do all students have a comma in the name? %b" printfn "\n head query operator" query { - for student in studentsQueryable do + for student in db.Student do head } |> (fun student -> printfn "Found the head student with StudentID = %d" student.StudentID) @@ -1606,7 +1606,7 @@ query { printfn "\n skip query operator" query { - for student in studentsQueryable do + for student in db.Student do skip 1 } |> Seq.iter (fun student -> printfn "StudentID = %d" student.StudentID) @@ -1621,14 +1621,14 @@ query { printfn "\n sumBy query operator" query { - for student in studentsQueryable do + for student in db.Student do sumBy student.StudentID } |> printfn "Sum of student IDs: %d" printfn "\n take query operator" query { - for student in studentsQueryable do + for student in db.Student do select student take 2 } @@ -1643,7 +1643,7 @@ query { printfn "\n sortByNullable query operator" query { - for student in studentsQueryable do + for student in db.Student do sortByNullable student.Age select student } @@ -1652,7 +1652,7 @@ query { printfn "\n sortByNullableDescending query operator" query { - for student in studentsQueryable do + for student in db.Student do sortByNullableDescending student.Age select student } @@ -1661,7 +1661,7 @@ query { printfn "\n thenByNullable query operator" query { - for student in studentsQueryable do + for student in db.Student do sortBy student.Name thenByNullable student.Age select student @@ -1671,7 +1671,7 @@ query { printfn "\n thenByNullableDescending query operator" query { - for student in studentsQueryable do + for student in db.Student do sortBy student.Name thenByNullableDescending student.Age select student @@ -1681,21 +1681,21 @@ query { printfn "All students: " query { - for student in studentsQueryable do + for student in db.Student do select student } |> Seq.iter (fun student -> printfn "%s %d %s" student.Name student.StudentID (student.Age.Print())) printfn "\nCount of students: " query { - for student in studentsQueryable do + for student in db.Student do count } |> (fun count -> printfn "Student count: %d" count) printfn "\nExists." query { - for student in studentsQueryable do + for student in db.Student do where (query { for courseSelection in db.CourseSelection do @@ -1706,7 +1706,7 @@ query { printfn "\n Group by age and count" query { - for n in studentsQueryable do + for n in db.Student do groupBy n.Age into g select (g.Key, g.Count()) } @@ -1714,7 +1714,7 @@ query { printfn "\n Group value by age." query { - for n in studentsQueryable do + for n in db.Student do groupValBy n.Age n.Age into g select (g.Key, g.Count()) } @@ -1722,7 +1722,7 @@ query { printfn "\nGroup students by age where age > 10." query { - for student in studentsQueryable do + for student in db.Student do groupBy student.Age into g where (g.Key.HasValue && g.Key.Value > 10) select (g, g.Key) @@ -1734,7 +1734,7 @@ query { printfn "\nGroup students by age and print counts of number of students at each age with more than 1 student." query { - for student in studentsQueryable do + for student in db.Student do groupBy student.Age into group where (group.Count() > 1) select (group.Key, group.Count()) @@ -1744,7 +1744,7 @@ query { printfn "\nGroup students by age and sum ages." query { - for student in studentsQueryable do + for student in db.Student do groupBy student.Age into g let total = query { for student in g do sumByNullable student.Age } select (g.Key, g.Count(), total) @@ -1756,7 +1756,7 @@ query { printfn "\nGroup students by age and count number of students at each age, and display all with count > 1 in descending order of count." query { - for student in studentsQueryable do + for student in db.Student do groupBy student.Age into g where (g.Count() > 1) sortByDescending (g.Count()) @@ -1771,7 +1771,7 @@ let idList = [1; 2; 5; 10] let idQuery = query { for id in idList do select id } query { - for student in studentsQueryable do + for student in db.Student do where (idQuery.Contains(student.StudentID)) select student } @@ -1780,7 +1780,7 @@ query { printfn "\nLook for students with Name match _e%% pattern and take first two." query { - for student in studentsQueryable do + for student in db.Student do where (SqlMethods.Like( student.Name, "_e%") ) select student take 2 @@ -1789,7 +1789,7 @@ query { printfn "\nLook for students with Name matching [abc]%% pattern." query { - for student in studentsQueryable do + for student in db.Student do where (SqlMethods.Like( student.Name, "[abc]%") ) select student } @@ -1797,7 +1797,7 @@ query { printfn "\nLook for students with name matching [^abc]%% pattern." query { - for student in studentsQueryable do + for student in db.Student do where (SqlMethods.Like( student.Name, "[^abc]%") ) select student } @@ -1805,7 +1805,7 @@ query { printfn "\nLook for students with name matching [^abc]%% pattern and select ID." query { - for n in studentsQueryable do + for n in db.Student do where (SqlMethods.Like( n.Name, "[^abc]%") ) select n.StudentID } @@ -1813,7 +1813,7 @@ query { printfn "\n Using Contains as a query filter." query { - for student in studentsQueryable do + for student in db.Student do where (student.Name.Contains("a")) select student } @@ -1822,14 +1822,14 @@ query { printfn "\nSearching for names from a list." let names = [|"a";"b";"c"|] query { - for student in studentsQueryable do + for student in db.Student do if names.Contains (student.Name) then select student } |> Seq.iter (fun student -> printfn "%s" student.Name) printfn "\nJoin Student and CourseSelection tables." query { - for student in studentsQueryable do + for student in db.Student do join selection in db.CourseSelection on (student.StudentID = selection.StudentID) select (student, selection) @@ -1838,7 +1838,7 @@ query { printfn "\nLeft Join Student and CourseSelection tables." query { - for student in studentsQueryable do + for student in db.Student do leftOuterJoin selection in db.CourseSelection on (student.StudentID = selection.StudentID) into result for selection in result.DefaultIfEmpty() do @@ -1853,7 +1853,7 @@ query { printfn "\nJoin with count" query { - for n in studentsQueryable do + for n in db.Student do join e in db.CourseSelection on (n.StudentID = e.StudentID) count @@ -1862,7 +1862,7 @@ query { printfn "\n Join with distinct." query { - for student in studentsQueryable do + for student in db.Student do join selection in db.CourseSelection on (student.StudentID = selection.StudentID) distinct @@ -1871,7 +1871,7 @@ query { printfn "\n Join with distinct and count." query { - for n in studentsQueryable do + for n in db.Student do join e in db.CourseSelection on (n.StudentID = e.StudentID) distinct @@ -1881,7 +1881,7 @@ query { printfn "\n Selecting students with age between 10 and 15." query { - for student in studentsQueryable do + for student in db.Student do where (student.Age.Value >= 10 && student.Age.Value < 15) select student } @@ -1889,7 +1889,7 @@ query { printfn "\n Selecting students with age either 11 or 12." query { - for student in studentsQueryable do + for student in db.Student do where (student.Age.Value = 11 || student.Age.Value = 12) select student } @@ -1897,7 +1897,7 @@ query { printfn "\n Selecting students in a certain age range and sorting." query { - for n in studentsQueryable do + for n in db.Student do where (n.Age.Value = 12 || n.Age.Value = 13) sortByNullableDescending n.Age select n @@ -1906,7 +1906,7 @@ query { printfn "\n Selecting students with certain ages, taking account of possibility of nulls." query { - for student in studentsQueryable do + for student in db.Student do where ((student.Age.HasValue && student.Age.Value = 11) || (student.Age.HasValue && student.Age.Value = 12)) @@ -1919,7 +1919,7 @@ query { printfn "\n Union of two queries." module Queries = let query1 = query { - for n in studentsQueryable do + for n in db.Student do select (n.Name, n.Age) } @@ -1934,7 +1934,7 @@ module Queries = printfn "\n Intersect of two queries." module Queries2 = let query1 = query { - for n in studentsQueryable do + for n in db.Student do select (n.Name, n.Age) } @@ -1948,7 +1948,7 @@ module Queries2 = printfn "\n Using if statement to alter results for special value." query { - for student in studentsQueryable do + for student in db.Student do select (if student.Age.HasValue && student.Age.Value = -1 then (student.StudentID, System.Nullable(100), student.Age) @@ -1958,7 +1958,7 @@ query { printfn "\n Using if statement to alter results special values." query { - for student in studentsQueryable do + for student in db.Student do select (if student.Age.HasValue && student.Age.Value = -1 then (student.StudentID, System.Nullable(100), student.Age) @@ -1970,7 +1970,7 @@ query { printfn "\n Multiple table select." query { - for student in studentsQueryable do + for student in db.Student do for course in db.Course do select (student, course) } @@ -1981,7 +1981,7 @@ query { printfn "\nMultiple Joins" query { - for student in studentsQueryable do + for student in db.Student do join courseSelection in db.CourseSelection on (student.StudentID = courseSelection.StudentID) join course in db.Course @@ -1992,7 +1992,7 @@ query { printfn "\nMultiple Left Outer Joins" query { - for student in studentsQueryable do + for student in db.Student do leftOuterJoin courseSelection in db.CourseSelection on (student.StudentID = courseSelection.StudentID) into g1 for courseSelection in g1.DefaultIfEmpty() do diff --git a/samples/snippets/fsharp/query-expressions/snippet2.fs b/samples/snippets/fsharp/query-expressions/snippet2.fs index aaa3c1f51c706..0f46243e7f27b 100644 --- a/samples/snippets/fsharp/query-expressions/snippet2.fs +++ b/samples/snippets/fsharp/query-expressions/snippet2.fs @@ -60,10 +60,13 @@ let courseSelections = [ { ID = 15; StudentID = 7; CourseID = 3 } ] -// Convert to queryable collections for LINQ operations -let studentsQueryable = students.AsQueryable() -let coursesQueryable = courses.AsQueryable() -let courseSelectionsQueryable = courseSelections.AsQueryable() +// Create a db object that mimics a database context +type DataContext() = + member _.Student = students.AsQueryable() + member _.Course = courses.AsQueryable() + member _.CourseSelection = courseSelections.AsQueryable() + +let db = DataContext() // Needed for some query operator examples: let data = [ 1; 5; 7; 11; 18; 21] \ No newline at end of file From d1680c7b3528681917561067c967d6cb100b22cc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Oct 2025 07:06:48 +0000 Subject: [PATCH 8/8] Replace in-memory examples with Entity Framework Core as requested Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- .../language-reference/query-expressions.md | 4 +- samples/snippets/fsharp/fssamples.fsproj | 3 +- .../fsharp/query-expressions/snippet1.fs | 35 +++-- .../fsharp/query-expressions/snippet2.fs | 121 +++++++++++------- 4 files changed, 102 insertions(+), 61 deletions(-) diff --git a/docs/fsharp/language-reference/query-expressions.md b/docs/fsharp/language-reference/query-expressions.md index dc7a245914a19..72b16c4f9b709 100644 --- a/docs/fsharp/language-reference/query-expressions.md +++ b/docs/fsharp/language-reference/query-expressions.md @@ -16,7 +16,7 @@ query { expression } ## Remarks -Query expressions are a type of computation expression similar to sequence expressions. Just as you specify a sequence by providing code in a sequence expression, you specify a set of data by providing code in a query expression. In a sequence expression, the `yield` keyword identifies data to be returned as part of the resulting sequence. In query expressions, the `select` keyword performs the same function. In addition to the `select` keyword, F# also supports a number of query operators that are much like the parts of a SQL SELECT statement. Here is an example of a simple query expression using in-memory data. +Query expressions are a type of computation expression similar to sequence expressions. Just as you specify a sequence by providing code in a sequence expression, you specify a set of data by providing code in a query expression. In a sequence expression, the `yield` keyword identifies data to be returned as part of the resulting sequence. In query expressions, the `select` keyword performs the same function. In addition to the `select` keyword, F# also supports a number of query operators that are much like the parts of a SQL SELECT statement. Here is an example of a simple query expression using Entity Framework Core to query a database. :::code language="fsharp" source="~/samples/snippets/fsharp/query-expressions/snippet1.fs"::: @@ -36,7 +36,7 @@ This table assumes a database in the following form: ![Diagram that shows a sample database.](./media/query-expressions/student-course-database.png) -The code in the tables that follow also assumes the following database connection code. Projects should add references to System.Linq. The code that creates this database is included at the end of this topic. +The code in the tables that follow also assumes the following database connection code using Entity Framework Core. Projects should add package references to `Microsoft.EntityFrameworkCore` and `Microsoft.EntityFrameworkCore.InMemory` (or another EF Core provider for production scenarios). This example uses the in-memory database provider for demonstration purposes, but the same query syntax works with any EF Core provider (SQL Server, PostgreSQL, etc.). :::code language="fsharp" source="~/samples/snippets/fsharp/query-expressions/snippet2.fs"::: diff --git a/samples/snippets/fsharp/fssamples.fsproj b/samples/snippets/fsharp/fssamples.fsproj index f5c21532184e3..13eaf156f581d 100644 --- a/samples/snippets/fsharp/fssamples.fsproj +++ b/samples/snippets/fsharp/fssamples.fsproj @@ -15,7 +15,8 @@ - + + diff --git a/samples/snippets/fsharp/query-expressions/snippet1.fs b/samples/snippets/fsharp/query-expressions/snippet1.fs index 6205d6997f674..52a838be5fef0 100644 --- a/samples/snippets/fsharp/query-expressions/snippet1.fs +++ b/samples/snippets/fsharp/query-expressions/snippet1.fs @@ -1,27 +1,42 @@ -// Modern F# query expression example using in-memory data +// F# query expression example using Entity Framework Core open System open System.Linq +open Microsoft.EntityFrameworkCore -// Simple data structures +// Entity type +[] type Customer = { CustomerID: int CompanyName: string ContactName: string } -// Sample data -let customers = [ - { CustomerID = 1; CompanyName = "Alfreds Futterkiste"; ContactName = "Maria Anders" } - { CustomerID = 2; CompanyName = "Ana Trujillo Emparedados y helados"; ContactName = "Ana Trujillo" } - { CustomerID = 3; CompanyName = "Antonio Moreno Taquería"; ContactName = "Antonio Moreno" } -] +// Database context +type NorthwindContext() = + inherit DbContext() + + [] + val mutable private customers: DbSet + member this.Customers with get() = this.customers and set v = this.customers <- v + + override _.OnConfiguring(optionsBuilder: DbContextOptionsBuilder) = + optionsBuilder.UseInMemoryDatabase("NorthwindDatabase") |> ignore -let db = customers.AsQueryable() +// Create and seed database +let db = + let context = new NorthwindContext() + context.Customers.AddRange([| + { CustomerID = 1; CompanyName = "Alfreds Futterkiste"; ContactName = "Maria Anders" } + { CustomerID = 2; CompanyName = "Ana Trujillo Emparedados y helados"; ContactName = "Ana Trujillo" } + { CustomerID = 3; CompanyName = "Antonio Moreno Taquería"; ContactName = "Antonio Moreno" } + |]) |> ignore + context.SaveChanges() |> ignore + context // A query expression let query1 = query { - for customer in db do + for customer in db.Customers do select customer } diff --git a/samples/snippets/fsharp/query-expressions/snippet2.fs b/samples/snippets/fsharp/query-expressions/snippet2.fs index 0f46243e7f27b..e9e296594b86b 100644 --- a/samples/snippets/fsharp/query-expressions/snippet2.fs +++ b/samples/snippets/fsharp/query-expressions/snippet2.fs @@ -1,72 +1,97 @@ -// Database setup example for query expressions +// Database setup example for query expressions using Entity Framework Core open System open System.Linq +open Microsoft.EntityFrameworkCore -// Define simple data types to represent our sample database +// Define entity types that map to database tables +[] type Student = { StudentID: int Name: string - Age: int option + Age: Nullable } +[] type Course = { CourseID: int CourseName: string } +[] type CourseSelection = { ID: int StudentID: int CourseID: int } -// Sample data -let students = [ - { StudentID = 1; Name = "Abercrombie, Kim"; Age = Some 10 } - { StudentID = 2; Name = "Abolrous, Hazen"; Age = Some 14 } - { StudentID = 3; Name = "Hance, Jim"; Age = Some 12 } - { StudentID = 4; Name = "Adams, Terry"; Age = Some 12 } - { StudentID = 5; Name = "Hansen, Claus"; Age = Some 11 } - { StudentID = 6; Name = "Penor, Lori"; Age = Some 13 } - { StudentID = 7; Name = "Perham, Tom"; Age = Some 12 } - { StudentID = 8; Name = "Peng, Yun-Feng"; Age = None } -] +// Define the database context using Entity Framework Core +type SchoolContext() = + inherit DbContext() + + [] + val mutable private student: DbSet + member this.Student with get() = this.student and set v = this.student <- v + + [] + val mutable private course: DbSet + member this.Course with get() = this.course and set v = this.course <- v + + [] + val mutable private courseSelection: DbSet + member this.CourseSelection with get() = this.courseSelection and set v = this.courseSelection <- v + + override _.OnConfiguring(optionsBuilder: DbContextOptionsBuilder) = + optionsBuilder.UseInMemoryDatabase("SchoolDatabase") |> ignore -let courses = [ - { CourseID = 1; CourseName = "Algebra I" } - { CourseID = 2; CourseName = "Trigonometry" } - { CourseID = 3; CourseName = "Algebra II" } - { CourseID = 4; CourseName = "History" } - { CourseID = 5; CourseName = "English" } - { CourseID = 6; CourseName = "French" } - { CourseID = 7; CourseName = "Chinese" } -] +// Create and seed the database +let createAndSeedDatabase() = + let context = new SchoolContext() + + // Seed data + context.Student.AddRange([| + { StudentID = 1; Name = "Abercrombie, Kim"; Age = Nullable(10) } + { StudentID = 2; Name = "Abolrous, Hazen"; Age = Nullable(14) } + { StudentID = 3; Name = "Hance, Jim"; Age = Nullable(12) } + { StudentID = 4; Name = "Adams, Terry"; Age = Nullable(12) } + { StudentID = 5; Name = "Hansen, Claus"; Age = Nullable(11) } + { StudentID = 6; Name = "Penor, Lori"; Age = Nullable(13) } + { StudentID = 7; Name = "Perham, Tom"; Age = Nullable(12) } + { StudentID = 8; Name = "Peng, Yun-Feng"; Age = Nullable() } + |]) |> ignore + + context.Course.AddRange([| + { CourseID = 1; CourseName = "Algebra I" } + { CourseID = 2; CourseName = "Trigonometry" } + { CourseID = 3; CourseName = "Algebra II" } + { CourseID = 4; CourseName = "History" } + { CourseID = 5; CourseName = "English" } + { CourseID = 6; CourseName = "French" } + { CourseID = 7; CourseName = "Chinese" } + |]) |> ignore + + context.CourseSelection.AddRange([| + { ID = 1; StudentID = 1; CourseID = 2 } + { ID = 2; StudentID = 1; CourseID = 3 } + { ID = 3; StudentID = 1; CourseID = 5 } + { ID = 4; StudentID = 2; CourseID = 2 } + { ID = 5; StudentID = 2; CourseID = 5 } + { ID = 6; StudentID = 2; CourseID = 6 } + { ID = 7; StudentID = 2; CourseID = 3 } + { ID = 8; StudentID = 3; CourseID = 2 } + { ID = 9; StudentID = 3; CourseID = 1 } + { ID = 10; StudentID = 4; CourseID = 2 } + { ID = 11; StudentID = 4; CourseID = 5 } + { ID = 12; StudentID = 4; CourseID = 2 } + { ID = 13; StudentID = 5; CourseID = 3 } + { ID = 14; StudentID = 5; CourseID = 2 } + { ID = 15; StudentID = 7; CourseID = 3 } + |]) |> ignore + + context.SaveChanges() |> ignore + context -let courseSelections = [ - { ID = 1; StudentID = 1; CourseID = 2 } - { ID = 2; StudentID = 1; CourseID = 3 } - { ID = 3; StudentID = 1; CourseID = 5 } - { ID = 4; StudentID = 2; CourseID = 2 } - { ID = 5; StudentID = 2; CourseID = 5 } - { ID = 6; StudentID = 2; CourseID = 6 } - { ID = 7; StudentID = 2; CourseID = 3 } - { ID = 8; StudentID = 3; CourseID = 2 } - { ID = 9; StudentID = 3; CourseID = 1 } - { ID = 10; StudentID = 4; CourseID = 2 } - { ID = 11; StudentID = 4; CourseID = 5 } - { ID = 12; StudentID = 4; CourseID = 2 } - { ID = 13; StudentID = 5; CourseID = 3 } - { ID = 14; StudentID = 5; CourseID = 2 } - { ID = 15; StudentID = 7; CourseID = 3 } -] - -// Create a db object that mimics a database context -type DataContext() = - member _.Student = students.AsQueryable() - member _.Course = courses.AsQueryable() - member _.CourseSelection = courseSelections.AsQueryable() - -let db = DataContext() +// Create the database context +let db = createAndSeedDatabase() // Needed for some query operator examples: let data = [ 1; 5; 7; 11; 18; 21] \ No newline at end of file