Expressions de requête (F#)
Les expressions de requête vous permettent d'interroger une source de données et de mettre à jour les données dans un formulaire souhaité. Les expressions de requête constituent la prise en charge LINQ en F#.
query { expression }
Notes
Les expressions de requête sont un type d'expression de calcul semblable aux expressions de séquence. Comme vous spécifiez une séquence en fournissant le code dans une expression de séquence, vous spécifiez un jeu de données en fournissant le code dans une expression de requête. Dans une expression de séquence, le mot clé yield identifie les données à retourner dans le cadre de la séquence résultante. Dans les expressions de requête, le mot clé select exécute la même fonction. En plus du mot clé select , F# prend également en charge un certain nombre d'opérateurs de requête qui sont comme les parties d'une instruction SELECT SQL. Voici un exemple d'expression de requête simple, avec le code qui connecte à la source OData Northwind.
// 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 }
query1
|> Seq.iter (fun customer -> printfn "Company: %s Contact: %s" customer.CompanyName customer.ContactName)
Dans l'exemple de code précédent, l'expression de requête est dans les accolades. La signification du code de l'expression est, retourne chaque client dans la table Customers dans la base de données dans les résultats de la requête. Les expressions de requête retournent un type qui implémente IQueryable et IEnumerable, et donc ils peuvent être itérés à l'aide de Seq module comme le montre l'exemple affiché.
Chaque type d'expression de calcul est généré à partir d'une classe de concepteur. La classe de concepteur pour l'expression de calcul de requête est QueryBuilder. Pour plus d'informations, consultez Expressions de calcul (F#) et Linq.QueryBuilder, classe (F#).
Opérateurs de requête
Les opérateurs de requête permettent de spécifier des détails de la requête, telle que pour mettre les critères des enregistrements à retourner, ou spécifiez l'ordre de tri des résultats. La source de requête doit prendre en charge l'opérateur de requête. Si vous essayez d'utiliser un opérateur de requête non pris en charge, NotSupportedException sera levée.
Uniquement des expressions qui peuvent être traduites en SQL sont autorisées dans les expressions de requête. Par exemple, aucun appel à fonction n´est autorisé dans les expressions lorsque vous utilisez l'opérateur de requête where .
Le tableau 1 illustre les opérateurs de requête disponibles. En outre, consultez Table2, qui compare des requêtes SQL et les expressions de requête équivalentes F# plus loin dans cette rubrique. Certains opérateurs de requête ne sont pas pris en charge par certain fournisseurs de type. En particulier, le type de fournisseur OData est limité dans les opérateurs de requête qu'il prend en charge en raison des restrictions OData. Pour plus d'informations, consultez Fournisseur de type ODataService (F#).
Ce tableau suppose une base de données sous la forme suivante :
Exemple de diagramme de base de données
Le code dans les tables qui suivent suppose également le code suivant de connexion de base de données. Les projets devraient ajouter des références aux assemblies System.Data, System.Data.Linq et FSharp.Data.TypeProviders. Le code qui crée cette base de données est inclus à la fin de cette rubrique.
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()
// Needed for some query operator examples:
let data = [ 1; 5; 7; 11; 18; 21]
Table 1.Opérateurs de requête
Opérateur |
Description |
contains |
Détermine si les éléments sélectionnés incluent un élément spécifié.
|
count |
Retourne le nombre d'éléments sélectionnés.
|
last |
Sélectionne le dernier élément de ceux sélectionnés jusqu'à présent.
|
lastOrDefault |
Sélectionne le dernier élément de ceux sélectionnés jusqu'ici, ou une valeur par défaut si aucun élément n'est trouvé.
|
exactlyOne |
Sélectionne l'élément unique et spécifique sélectionné jusqu'à présent. Si plusieurs éléments sont présents, une exception est levée.
|
exactlyOneOrDefault |
Sélectionne l'élément unique et spécifique de ceux sélectionnés jusqu'ici, ou une valeur par défaut si cet élément est introuvable.
|
headOrDefault |
Sélectionne le premier élément de ceux sélectionnés jusqu'ici, ou une valeur par défaut si la séquence ne contient aucun élément.
|
select |
Projette chacun des éléments sélectionnés jusqu'à présent.
|
where |
Sélectionne des éléments selon un prédicat spécifié.
|
minBy |
Sélectionne une valeur pour chaque élément sélectionné jusqu'ici et retourne la valeur résultante minimale.
|
maxBy |
Sélectionne une valeur pour chaque élément sélectionné jusqu'ici et retourne la valeur résultante maximale.
|
groupBy |
Regroupe les éléments sélectionnés jusqu'à présent en fonction d'un sélecteur de clé spécifié.
|
sortBy |
Trie les éléments sélectionnés jusqu'ici dans l'ordre croissant par la clé de tri donnée.
|
sortByDescending |
Trie les éléments sélectionnés jusqu'ici dans l'ordre décroissant par la clé de tri donnée.
|
thenBy |
Réalise un classement postérieur des éléments déjà sélectionnés dans l'ordre croissant par la clé de tri donnée. Cet opérateur ne peut être utilisée qu´après sortBy, sortByDescending, thenBy, ou thenByDescending.
|
thenByDescending |
Réalise un classement postérieur des éléments déjà sélectionnés dans l'ordre décroissant par la clé de tri donnée. Cet opérateur ne peut être utilisée qu´après sortBy, sortByDescending, thenBy, ou thenByDescending.
|
groupValBy |
Sélectionne une valeur pour chaque élément sélectionné jusqu'ici et qui regroupe les éléments par la clé donnée.
|
join |
Corrèle deux jeux de valeurs sélectionnées basées sur des clés de correspondance. Notez que l'ordre des clés autour du signe = dans une expression de jointure est important. Dans toutes les jointures, si la ligne est fractionnée après le symbole -> , la mise en retrait doit être mise en retrait au moins jusqu´au mot clé for.
|
groupJoin |
Corrèle deux ensembles de valeurs sélectionnées en fonction des clés correspondantes et regroupe les résultats. Notez que l'ordre des clés autour du signe = dans une expression de jointure est important.
|
leftOuterJoin |
Corrèle deux ensembles de valeurs sélectionnées en fonction des clés correspondantes et regroupe les résultats. Si un groupe est vide, un groupe avec une valeur par défaut unique est utilisé à la place. Notez que l'ordre des clés autour du signe = dans une expression de jointure est important.
|
sumByNullable |
Sélectionne une valeur nullable pour chaque élément sélectionné jusqu'ici et qui renvoie la somme des valeurs suivantes. Le cas échéant, nullable n'a pas de valeur, il est ignoré.
|
minByNullable |
Sélectionne une valeur nullable pour chaque élément sélectionné jusqu'ici et qui renvoie la valeur minimale de ces suivantes. Le cas échéant, nullable n'a pas de valeur, il est ignoré.
|
maxByNullable |
Sélectionne une valeur nullable pour chaque élément sélectionné jusqu'ici et qui renvoie la valeur maximale de ces suivantes. Le cas échéant, nullable n'a pas de valeur, il est ignoré.
|
averageByNullable |
Sélectionne une valeur nullable pour chaque élément sélectionné jusqu'ici et qui renvoie la moyenne des valeurs suivantes. Le cas échéant, nullable n'a pas de valeur, il est ignoré.
|
averageBy |
Sélectionne une valeur pour chaque élément sélectionné jusqu'ici et qui renvoie la moyenne des valeurs suivantes.
|
distinct |
Sélectionne des éléments distincts des éléments sélectionnés jusqu'à présent.
|
exists |
Détermine si des éléments sélectionnés jusqu´ici satisfont à une condition.
|
find |
Sélectionne le premier élément sélectionné jusqu'ici et qui satisfait à une condition spécifiée.
|
all |
Détermine si tous les éléments sélectionnés jusqu´ici satisfont à une condition.
|
head |
Sélectionne le premier élément de ceux sélectionnés jusqu'à présent.
|
nth |
Sélectionne l'élément au niveau d'un index spécifié parmi ceux sélectionnés jusqu'ici.
|
skip |
Ignore un nombre spécifié d'éléments déjà sélectionnés et sélectionne ensuite ceux restants.
|
skipWhile |
Ignore des éléments dans une séquence tant que la condition spécifiée a la valeur true, puis sélectionne les éléments restants.
|
sumBy |
Sélectionne une valeur pour chaque élément sélectionné jusqu'ici et qui renvoie la somme des valeurs suivantes.
|
take |
Sélectionne un nombre spécifié d'éléments contigus à partir de ceux sélectionnés jusqu'ici.
|
takeWhile |
Sélectionne des éléments d'une séquence tant que la condition spécifiée a la valeur true, puis ignore les éléments restants.
|
sortByNullable |
Trie les éléments sélectionnés jusqu'ici dans l'ordre croissant par la clé de tri nullable.
|
sortByNullableDescending |
Trie les éléments sélectionnés jusqu'ici dans l'ordre décroissant par la clé de tri nullable.
|
thenByNullable |
Réalise un classement postérieur des éléments déjà sélectionnés dans l'ordre croissant par la clé de tri nullable donnée. Cet opérateur ne peut être utilisée immédiatement qu´après sortBy, sortByDescending, thenBy, ou thenByDescending, ou leurs variantes nullables.
|
thenByNullableDescending |
Réalise un classement postérieur des éléments déjà sélectionnés dans l'ordre décroissant par la clé de tri nullable donnée. Cet opérateur ne peut être utilisée immédiatement qu´après sortBy, sortByDescending, thenBy, ou thenByDescending, ou leurs variantes nullables.
|
Comparaison de Transact-SQL et des expressions de requête F#
Le tableau suivant affiche certaines requêtes Transact-SQL courantes et leurs équivalents en F#. Le code dans cette table suppose également la même base de données que le tableau précédent et le même code initial pour installer le fournisseur de type.
Table 2.Transact-SQL et expressions de requête F#
Le code ci-dessous peut être utilisé pour créer la base de données pour ces exemples.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
USE [master];
GO
IF EXISTS (SELECT * FROM sys.databases WHERE name = 'MyDatabase')
DROP DATABASE MyDatabase;
GO
-- Create the MyDatabase database.
CREATE DATABASE MyDatabase COLLATE SQL_Latin1_General_CP1_CI_AS;
GO
-- Specify a simple recovery model
-- to keep the log growth to a minimum.
ALTER DATABASE MyDatabase
SET RECOVERY SIMPLE;
GO
USE MyDatabase;
GO
CREATE TABLE [dbo].[Course] (
[CourseID] INT NOT NULL,
[CourseName] NVARCHAR (50) NOT NULL,
PRIMARY KEY CLUSTERED ([CourseID] ASC)
);
CREATE TABLE [dbo].[Student] (
[StudentID] INT NOT NULL,
[Name] NVARCHAR (50) NOT NULL,
[Age] INT NULL,
PRIMARY KEY CLUSTERED ([StudentID] ASC)
);
CREATE TABLE [dbo].[CourseSelection] (
[ID] INT NOT NULL,
[StudentID] INT NOT NULL,
[CourseID] INT NOT NULL,
PRIMARY KEY CLUSTERED ([ID] ASC),
CONSTRAINT [FK_CourseSelection_ToTable] FOREIGN KEY ([StudentID]) REFERENCES [dbo].[Student] ([StudentID]) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT [FK_CourseSelection_Course_1] FOREIGN KEY ([CourseID]) REFERENCES [dbo].[Course] ([CourseID]) ON DELETE NO ACTION ON UPDATE NO ACTION
);
CREATE TABLE [dbo].[LastStudent] (
[StudentID] INT NOT NULL,
[Name] NVARCHAR (50) NOT NULL,
[Age] INT NULL,
PRIMARY KEY CLUSTERED ([StudentID] ASC)
);
-- Insert data into the tables.
USE MyDatabase
INSERT INTO Course (CourseID, CourseName)
VALUES(1, 'Algebra I');
INSERT INTO Course (CourseID, CourseName)
VALUES(2, 'Trigonometry');
INSERT INTO Course (CourseID, CourseName)
VALUES(3, 'Algebra II');
INSERT INTO Course (CourseID, CourseName)
VALUES(4, 'History');
INSERT INTO Course (CourseID, CourseName)
VALUES(5, 'English');
INSERT INTO Course (CourseID, CourseName)
VALUES(6, 'French');
INSERT INTO Course (CourseID, CourseName)
VALUES(7, 'Chinese');
INSERT INTO Student (StudentID, Name, Age)
VALUES(1, 'Abercrombie, Kim', 10);
INSERT INTO Student (StudentID, Name, Age)
VALUES(2, 'Abolrous, Hazen', 14);
INSERT INTO Student (StudentID, Name, Age)
VALUES(3, 'Hance, Jim', 12);
INSERT INTO Student (StudentID, Name, Age)
VALUES(4, 'Adams, Terry', 12);
INSERT INTO Student (StudentID, Name, Age)
VALUES(5, 'Hansen, Claus', 11);
INSERT INTO Student (StudentID, Name, Age)
VALUES(6, 'Penor, Lori', 13);
INSERT INTO Student (StudentID, Name, Age)
VALUES(7, 'Perham, Tom', 12);
INSERT INTO Student (StudentID, Name, Age)
VALUES(8, 'Peng, Yun-Feng', NULL);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(1, 1, 2);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(2, 1, 3);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(3, 1, 5);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(4, 2, 2);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(5, 2, 5);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(6, 2, 6);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(7, 2, 3);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(8, 3, 2);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(9, 3, 1);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(10, 4, 2);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(11, 4, 5);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(12, 4, 2);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(13, 5, 3);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(14, 5, 2);
INSERT INTO CourseSelection (ID, StudentID, CourseID)
VALUES(15, 7, 3);
Le code suivant contient un exemple de code qui apparaît dans cette rubrique.
#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
[<Generate>]
type schema = SqlDataConnection<"Data Source=SERVER\INSTANCE;Initial Catalog=MyDatabase;Integrated Security=SSPI;">
let db = schema.GetDataContext()
let student = db.Student
let data = [1; 5; 7; 11; 18; 21]
open System
type Nullable<'T when 'T : ( new : unit -> 'T) and 'T : struct and 'T :> ValueType > with
member this.Print() =
if (this.HasValue) then this.Value.ToString()
else "NULL"
printfn "\ncontains query operator"
query {
for student in db.Student do
select student.Age.Value
contains 11
}
|> printfn "Is at least one student age 11? %b"
printfn "\ncount query operator"
query {
for student in db.Student do
select student
count
}
|> printfn "Number of students: %d"
printfn "\nlast query operator."
let num =
query {
for number in data do
sortBy number
last
}
printfn "Last number: %d" num
open Microsoft.FSharp.Linq
printfn "\nlastOrDefault query operator."
query {
for number in data do
sortBy number
lastOrDefault
}
|> printfn "lastOrDefault: %d"
printfn "\nexactlyOne query operator."
let student2 =
query {
for student in db.Student do
where (student.StudentID = 1)
select student
exactlyOne
}
printfn "Student with StudentID = 1 is %s" student2.Name
printfn "\nexactlyOneOrDefault query operator."
let student3 =
query {
for student in db.Student do
where (student.StudentID = 1)
select student
exactlyOneOrDefault
}
printfn "Student with StudentID = 1 is %s" student3.Name
printfn "\nheadOrDefault query operator."
let student4 =
query {
for student in db.Student do
select student
headOrDefault
}
printfn "head student is %s" student4.Name
printfn "\nselect query operator."
query {
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 db.Student do
where (student.StudentID > 4)
select student
}
|> Seq.iter (fun student -> printfn "StudentID, Name: %d %s" student.StudentID student.Name)
printfn "\nminBy query operator."
let student5 =
query {
for student in db.Student do
minBy student.StudentID
}
printfn "\nmaxBy query operator."
let student6 =
query {
for student in db.Student do
maxBy student.StudentID
}
printfn "\ngroupBy query operator."
query {
for student in db.Student do
groupBy student.Age into g
select (g.Key, g.Count())
}
|> Seq.iter (fun (age, count) -> printfn "Age: %s Count at that age: %d" (age.Print()) count)
printfn "\nsortBy query operator."
query {
for student in db.Student do
sortBy student.Name
select student
}
|> Seq.iter (fun student -> printfn "StudentID, Name: %d %s" student.StudentID student.Name)
printfn "\nsortByDescending query operator."
query {
for student in db.Student do
sortByDescending student.Name
select student
}
|> Seq.iter (fun student -> printfn "StudentID, Name: %d %s" student.StudentID student.Name)
printfn "\nthenBy query operator."
query {
for student in db.Student do
where student.Age.HasValue
sortBy student.Age.Value
thenBy student.Name
select student
}
|> Seq.iter (fun student -> printfn "StudentID, Name: %d %s" student.Age.Value student.Name)
printfn "\nthenByDescending query operator."
query {
for student in db.Student do
where student.Age.HasValue
sortBy student.Age.Value
thenByDescending student.Name
select student
}
|> Seq.iter (fun student -> printfn "StudentID, Name: %d %s" student.Age.Value student.Name)
printfn "\ngroupValBy query operator."
query {
for student in db.Student do
groupValBy student.Name student.Age into g
select (g, g.Key, g.Count())
}
|> Seq.iter (fun (group, age, count) ->
printfn "Age: %s Count at that age: %d" (age.Print()) count
group |> Seq.iter (fun name -> printfn "Name: %s" name))
printfn "\n sumByNullable query operator"
query {
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 db.Student do
minByNullable student.Age
}
|> (fun age -> printfn "Minimum age: %s" (age.Print()))
printfn "\n maxByNullable"
query {
for student in db.Student do
maxByNullable student.Age
}
|> (fun age -> printfn "Maximum age: %s" (age.Print()))
printfn "\n averageBy"
query {
for student in db.Student do
averageBy (float student.StudentID)
}
|> printfn "Average student ID: %f"
printfn "\n averageByNullable"
query {
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 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 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 db.Student do
head
}
|> (fun student -> printfn "Found the head student with StudentID = %d" student.StudentID)
printfn "\n nth query operator"
query {
for numbers in data do
nth 3
}
|> printfn "Third number is %d"
printfn "\n skip query operator"
query {
for student in db.Student do
skip 1
}
|> Seq.iter (fun student -> printfn "StudentID = %d" student.StudentID)
printfn "\n skipWhile query operator"
query {
for number in data do
skipWhile (number < 3)
select number
}
|> Seq.iter (fun number -> printfn "Number = %d" number)
printfn "\n sumBy query operator"
query {
for student in db.Student do
sumBy student.StudentID
}
|> printfn "Sum of student IDs: %d"
printfn "\n take query operator"
query {
for student in db.Student do
select student
take 2
}
|> Seq.iter (fun student -> printfn "StudentID = %d" student.StudentID)
printfn "\n takeWhile query operator"
query {
for number in data do
takeWhile (number < 10)
}
|> Seq.iter (fun number -> printfn "Number = %d" number)
printfn "\n sortByNullable query operator"
query {
for student in db.Student do
sortByNullable student.Age
select student
}
|> Seq.iter (fun student ->
printfn "StudentID, Name, Age: %d %s %s" student.StudentID student.Name (student.Age.Print()))
printfn "\n sortByNullableDescending query operator"
query {
for student in db.Student do
sortByNullableDescending student.Age
select student
}
|> Seq.iter (fun student ->
printfn "StudentID, Name, Age: %d %s %s" student.StudentID student.Name (student.Age.Print()))
printfn "\n thenByNullable query operator"
query {
for student in db.Student do
sortBy student.Name
thenByNullable student.Age
select student
}
|> Seq.iter (fun student ->
printfn "StudentID, Name, Age: %d %s %s" student.StudentID student.Name (student.Age.Print()))
printfn "\n thenByNullableDescending query operator"
query {
for student in db.Student do
sortBy student.Name
thenByNullableDescending student.Age
select student
}
|> Seq.iter (fun student ->
printfn "StudentID, Name, Age: %d %s %s" student.StudentID student.Name (student.Age.Print()))
printfn "All students: "
query {
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 db.Student do
count
}
|> (fun count -> printfn "Student count: %d" count)
printfn "\nExists."
query {
for student in db.Student do
where (query { for courseSelection in db.CourseSelection do
exists (courseSelection.StudentID = student.StudentID) })
select student }
|> Seq.iter (fun student -> printfn "%A" student.Name)
printfn "\n Group by age and count"
query {
for n in db.Student do
groupBy n.Age into g
select (g.Key, g.Count())
}
|> Seq.iter (fun (age, count) -> printfn "%s %d" (age.Print()) count)
printfn "\n Group value by age."
query {
for n in db.Student do
groupValBy n.Age n.Age into g
select (g.Key, g.Count())
}
|> Seq.iter (fun (age, count) -> printfn "%s %d" (age.Print()) count)
printfn "\nGroup students by age where age > 10."
query {
for student in db.Student do
groupBy student.Age into g
where (g.Key.HasValue && g.Key.Value > 10)
select (g, g.Key)
}
|> Seq.iter (fun (students, age) ->
printfn "Age: %s" (age.Value.ToString())
students
|> Seq.iter (fun student -> printfn "%s" student.Name))
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
groupBy student.Age into group
where (group.Count() > 1)
select (group.Key, group.Count())
}
|> Seq.iter (fun (age, ageCount) ->
printfn "Age: %s Count: %d" (age.Print()) ageCount)
printfn "\nGroup students by age and sum ages."
query {
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)
}
|> Seq.iter (fun (age, count, total) ->
printfn "Age: %d" (age.GetValueOrDefault())
printfn "Count: %d" count
printfn "Total years: %s" (total.ToString()))
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
groupBy student.Age into g
where (g.Count() > 1)
sortByDescending (g.Count())
select (g.Key, g.Count())
}
|> Seq.iter (fun (age, myCount) ->
printfn "Age: %s" (age.Print())
printfn "Count: %d" myCount)
printfn "\n Select students from a set of IDs"
let idList = [1; 2; 5; 10]
let idQuery = query { for id in idList do
select id }
query {
for student in db.Student do
where (idQuery.Contains(student.StudentID))
select student
}
|> Seq.iter (fun student ->
printfn "Name: %s" student.Name)
printfn "\nLook for students with Name match _e%% pattern and take first two."
query {
for student in db.Student do
where (SqlMethods.Like( student.Name, "_e%") )
select student
take 2
}
|> Seq.iter (fun student -> printfn "%s" student.Name)
printfn "\nLook for students with Name matching [abc]%% pattern."
query {
for student in db.Student do
where (SqlMethods.Like( student.Name, "[abc]%") )
select student
}
|> Seq.iter (fun student -> printfn "%s" student.Name)
printfn "\nLook for students with name matching [^abc]%% pattern."
query {
for student in db.Student do
where (SqlMethods.Like( student.Name, "[^abc]%") )
select student
}
|> Seq.iter (fun student -> printfn "%s" student.Name)
printfn "\nLook for students with name matching [^abc]%% pattern and select ID."
query {
for n in db.Student do
where (SqlMethods.Like( n.Name, "[^abc]%") )
select n.StudentID
}
|> Seq.iter (fun id -> printfn "%d" id)
printfn "\n Using Contains as a query filter."
query {
for student in db.Student do
where (student.Name.Contains("a"))
select student
}
|> Seq.iter (fun student -> printfn "%s" student.Name)
printfn "\nSearching for names from a list."
let names = [|"a";"b";"c"|]
query {
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 db.Student do
join (for selection in db.CourseSelection ->
student.StudentID = selection.StudentID)
select (student, selection)
}
|> Seq.iter (fun (student, selection) -> printfn "%d %s %d" student.StudentID student.Name selection.CourseID)
printfn "\nLeft Join Student and CourseSelection tables."
query {
for student in db.Student do
leftOuterJoin (for selection in db.CourseSelection ->
student.StudentID = selection.StudentID) into result
for selection in result.DefaultIfEmpty() do
select (student, selection)
}
|> Seq.iter (fun (student, selection) ->
let selectionID, studentID, courseID =
match selection with
| null -> "NULL", "NULL", "NULL"
| sel -> (sel.ID.ToString(), sel.StudentID.ToString(), sel.CourseID.ToString())
printfn "%d %s %d %s %s %s" student.StudentID student.Name (student.Age.GetValueOrDefault()) selectionID studentID courseID)
printfn "\nJoin with count"
query {
for n in db.Student do
join (for e in db.CourseSelection -> n.StudentID = e.StudentID)
count
}
|> printfn "%d"
printfn "\n Join with distinct."
query {
for student in db.Student do
join (for selection in db.CourseSelection ->
student.StudentID = selection.StudentID)
distinct
}
|> Seq.iter (fun (student, selection) -> printfn "%s %d" student.Name selection.CourseID)
printfn "\n Join with distinct and count."
query {
for n in db.Student do
join (for e in db.CourseSelection -> n.StudentID = e.StudentID)
distinct
count
}
|> printfn "%d"
printfn "\n Selecting students with age between 10 and 15."
query {
for student in db.Student do
where (student.Age.Value >= 10 && student.Age.Value < 15)
select student
}
|> Seq.iter (fun student -> printfn "%s" student.Name)
printfn "\n Selecting students with age either 11 or 12."
query {
for student in db.Student do
where (student.Age.Value = 11 || student.Age.Value = 12)
select student
}
|> Seq.iter (fun student -> printfn "%s" student.Name)
printfn "\n Selecting students in a certain age range and sorting."
query {
for n in db.Student do
where (n.Age.Value = 12 || n.Age.Value = 13)
sortByNullableDescending n.Age
select n
}
|> Seq.iter (fun student -> printfn "%s %s" student.Name (student.Age.Print()))
printfn "\n Selecting students with certain ages, taking account of possibility of nulls."
query {
for student in db.Student do
where ((student.Age.HasValue && student.Age.Value = 11) ||
(student.Age.HasValue && student.Age.Value = 12))
sortByDescending student.Name
select student.Name
take 2
}
|> Seq.iter (fun name -> printfn "%s" name)
printfn "\n Union of two queries."
module Queries =
let query1 = query {
for n in db.Student do
select (n.Name, n.Age)
}
let query2 = query {
for n in db.LastStudent do
select (n.Name, n.Age)
}
query2.Union (query1)
|> Seq.iter (fun (name, age) -> printfn "%s %s" name (age.Print()))
printfn "\n Intersect of two queries."
module Queries2 =
let query1 = query {
for n in db.Student do
select (n.Name, n.Age)
}
let query2 = query {
for n in db.LastStudent do
select (n.Name, n.Age)
}
query1.Intersect(query2)
|> Seq.iter (fun (name, age) -> printfn "%s %s" name (age.Print()))
printfn "\n Using if statement to alter results for special value."
query {
for student in db.Student do
select (if student.Age.HasValue && student.Age.Value = -1 then
(student.StudentID, System.Nullable<int>(100), student.Age)
else (student.StudentID, student.Age, student.Age))
}
|> Seq.iter (fun (id, value, age) -> printfn "%d %s %s" id (value.Print()) (age.Print()))
printfn "\n Using if statement to alter results special values."
query {
for student in db.Student do
select (if student.Age.HasValue && student.Age.Value = -1 then
(student.StudentID, System.Nullable<int>(100), student.Age)
elif student.Age.HasValue && student.Age.Value = 0 then
(student.StudentID, System.Nullable<int>(100), student.Age)
else (student.StudentID, student.Age, student.Age))
}
|> Seq.iter (fun (id, value, age) -> printfn "%d %s %s" id (value.Print()) (age.Print()))
printfn "\n Multiple table select."
query {
for student in db.Student do
for course in db.Course do
select (student, course)
}
|> Seq.iteri (fun index (student, course) ->
if (index = 0) then printfn "StudentID Name Age CourseID CourseName"
printfn "%d %s %s %d %s" student.StudentID student.Name (student.Age.Print()) course.CourseID course.CourseName)
printfn "\nMultiple Joins"
query {
for student in db.Student do
join courseSelection in db.CourseSelection on
(student.StudentID = courseSelection.StudentID)
join course in db.Course on
(courseSelection.CourseID = course.CourseID)
select (student.Name, course.CourseName)
}
|> Seq.iter (fun (studentName, courseName) -> printfn "%s %s" studentName courseName)
printfn "\nMultiple Left Outer Joins"
query {
for student in db.Student do
leftOuterJoin (for courseSelection in db.CourseSelection ->
student.StudentID = courseSelection.StudentID) into g1
for courseSelection in g1.DefaultIfEmpty() do
leftOuterJoin (for course in db.Course ->
courseSelection.CourseID = course.CourseID) into g2
for course in g2.DefaultIfEmpty() do
select (student.Name, course.CourseName)
}
|> Seq.iter (fun (studentName, courseName) -> printfn "%s %s" studentName courseName)
Et voici la sortie complète lorsque ce code est exécuté dans F# interactive.
Voir aussi
Référence
Linq.QueryBuilder, classe (F#)