Linq To Entity
Interroger la base de données via EF et le modèle généré se fait via un langage particulier
appelé Linq to Entity (Language Integrated Query)
Ce langage permet d’écrire des requêtes qui seront ensuite transformées en langage SQL (ou Oracle ou MySQL) à partir
d’un langage typé.
Les requêtes LINQ s’exécutent toujours dans le contexte du modèle EF.
SELECTION
Cette requête LINQ permet de récupérer tous les objets Eleves
de votre base AutoEcole
:
var query = from el in context.eleves
select el;
var allEleves = query.ToList();
foreach (var eleve in allEleves)
{
Console.WriteLine($"{eleve.nom} {eleve.prenom}");
}
La variable query
représente la requête à exécuter sur votre base de données.
La variable allEleves
représente la List<Eleves>
issu de l’exécution de votre requête.
SELECT * FROM context.eleves el
(...)
Clause where
Nous pouvons avoir aussi :
var query = from el in context.eleves
where el.creditHoraire >10
select el;
var allEleves = query.ToList();
foreach (var eleve in allEleves)
{
Console.WriteLine($"{eleve.nom} {eleve.prenom}");
}
Dans ce cas, comme en SQL, nous affectons une contrainte where
à la liste.
Les tests dans where peuvent contenir plusieurs critères, avec les opérateurs logiques &&
(and), ||
(or) ==
(équivalent).
SELECT * FROM context.eleves el
WHERE el.creditHoraire >10
...
Types anonymes
Voici une nouvelle formulation.
var query = from el in context.eleves
where el.creditHoraire > 10
select new { FirstName = el.nom, LastName = el.prenom };
var allEleves = query.ToList();
foreach (var eleve in allEleves)
{
Console.WriteLine($"{eleve.FirstName} {eleve.LastName}");
}
Quelques explications :
from
permet de définir la source de données (spécifiée après le mot clécontext
) et une variable de portée locale qui représente les éléments dans la séquence source (ici, c’estel
). Pour le reste de la requête, on peut exploiter les champs de cette variable (avecel.creditHoraire
par exemple).where
nous permet de définir les conditions de la requête, pour filtrer juste sur les valeurs qui nous intéressentselect
permet de définir les variables de sortie. Ici, nous créons un type à la volée avec le mot clénew
. Le résultat est un ensemble de types Anonymes contenant les propriétés voulues.FirstName
et.LastName
.- L’affichage se fait à partir de ces nouvelles variables.
SELECT el.nom AS FirstName, el.prenom AS LastName FROM context.eleves el WHERE el.creditHoraire >10 (...)
Clause orderby
Cette instruction se place avant le select
.
var query = from el in m.eleves
where el.creditHoraire > 10
orderby el.creditHoraire descending
select el;
var allEleves = query.ToList();
foreach (var eleve in allEleves)
{
Console.WriteLine($"{eleve.nom} {eleve.prenom}");
}
Ici, nous avons ajouté une clause orderby
, suivie du champ sur lequel faire le tri, et l’ordre.
SELECT *
FROM context.eleves el
WHERE el.creditHoraire >10
ORDER BY el.creditHoraire DESC
(...)
Les fonctions d’agrégation
- Max() : valeur maximale dans la collection (ou dernier par ordre alphabétique)
- Min() : valeur minimale dans la collection (ou premier par ordre alphabétique)
- Count() : total d’éléments dans la collection
- Average() : moyenne des valeurs de la collection (types numériques uniquement)
- Sum() : total des valeurs de la collection (types numériques uniquement) Voici des exemples d’application :
var query = from el in m.eleves
where el.creditHoraire > 10
orderby el.creditHoraire descending
select el.creditHoraire;
var maxEleves = query.Max();
var sumEleves = query.Sum();
var countEleves = query.Count() ;
Juste un exemple pour MAX()
le reste est équivalent
SELECT MAX(*)
FROM context.eleves el
WHERE el.creditHoraire >10
ORDER BY el.creditHoraire DESC
...
L’opération de manipulation d’ensemble DISTINCT
- DISTINCT : supprime les doublons Voici des exemples d’application :
var query = from el in m.eleves
where el.creditHoraire > 10
orderby el.creditHoraire descending
select el.creditHoraire;
var distinctEleves = query.Distinct()
SELECT DISTINCT el.creditHoraire
FROM context.eleves el
WHERE el.creditHoraire >10
ORDER BY el.creditHoraire DESC
...
JOINTURE
Relation explicites
L’idée ici est de récupérer des éléments suivants une jointure SQL en utilisant la syntaxe from
:
var query = from e in context.lecons
from r in context.vehicules
from t in context.eleves
where t.id == 46
select e;
Le gros avantage ici, c’est qu’il est inutile de spécifier les jointures à utiliser, car elles sont déjà connues par le modèle AutoEcole.
Relations non explicites
Ce n’est pas le cas dans notre modèle, mais si votre base de données ne contient pas de relations (et donc le modèle ne les connaissant pas) vous pouvez réaliser une relation explicite comme ceci :
var query = from t in context.eleves
join r in context.lecons on t.id equals r.idEleve
where t.nom == "Ardi"
select r;
join … in … on … equals
est la syntaxe qui permet d’établir la relation explicite entre
deux entités (donc 2 tables).
REGROUPEMENT
Il s’agit de grouper les éléments dans une nouvelle structure. Nous allons utiliser le
concept qde type anonyme dans la requête LINQ.
Un type anonyme permet de créer un objet dynamiquement sans forcément avoir au préalable
écrit la classe correspondante.
Dans une fonction de regroupement, on a souvent une structure différente de la structure de la
table d’où l’utilisation de type anonyme.
Voici un exemple sur la table Lecons
on souhaite avoir les lecons
pour chaque eleves
:
var query = from p in context.lecons
group p by new { p.id, p.idEleve } into LeconsGroupbyEleve
select new
{
LeconId = LeconsGroupbyEleve.Key.id,
EleveId = LeconsGroupbyEleve.Key.idEleve
};
foreach (var p in query.ToList())
{Console.WriteLine($"{p.LeconId} {p.EleveId}");}
Les fonctions d’agrégation
Somme (sum) :
var query = from l in this.mesDonnesEF.lecons
group l by l.idEleve into groupeLecon
join e in this.mesDonnesEF.eleves on groupeLecon.Key equals e.id
select new
{
nom = e.nom,
totalHeure = groupeLecon.Sum(cumul => cumul.duree )
};
cumul => cumul.duree
est une expression lambda. Elle gagne en performance par rapport à une expression classique.
Cumul (Count)
var query = from l in this.mesDonnesEF.lecons
group l by l.numImmaVehicule into groupeVehicule
join v in this.mesDonnesEF.vehicules on groupeVehicule.Key equals v.numImma
select new
{
immatriculation = v.numImma,
NombreDeFois = groupeVehicule.Count()
};
Les types anonymes permettent une intégration des fonctions d’agrégation dans le select.
FILTRE
L’idée ici est de passer une variable comme nous aurions passé un paramètre. EF va générer une requête paramétrée et l’exécuter sur votre base :
String filtre = "1123YA93";
var query = from l in context.lecons
where l.numImmaVehicule.StartsWith(filtre)
select l;
StartWith()
est transformée en commande SQL Like
et la
variable de type string est bien remplacée par un paramètre nvarchar()
INSERTION
using (var context = new autoecoleEntities())
{
var nouvelEleve = new Eleve
{
Id = "e1",
Nom = "dupont",
Prenom = "jean"
};
context.Eleves.Add(nouvelEleve);
context.SaveChanges();
}
INSERT INTO context.eleves VALUES ('e1', 'dupont', 'jean')
...
MISE A JOUR
using (var context = new autoecoleEntities())
{
var eleveAModifier = context.Eleves
.Where(e => e.Prenom == "jean")
.FirstOrDefault();
if (eleveAModifier != null)
{
eleveAModifier.Nom = "yoyo";
context.SaveChanges();
}
}
UPDATE context.eleves SET nom='yoyo' WHERE prenom='jean'
...
SUPPRESSION
using (var context = new VotreDbContext())
{
// Méthode 1 : LINQ avec chargement
var elevesASupprimer = context.Eleves
.Where(e => e.Nom == "yoyo")
.ToList();
if (elevesASupprimer.Any())
{
context.Eleves.RemoveRange(elevesASupprimer);
context.SaveChanges();
}
}
DELETE FROM Eleves WHERE nom='yoyo'
...