Deneme
Masterclass SQL to LINQ LEFT JOIN : EF Core 10 et accès moderne aux données (Masterclass SQL To LINQ Left Join EF Core 10 Et Acces Moderne Aux Donnees)
Découvrez l'opérateur révolutionnaire LeftJoin introduit par EF Core 10 : suppression de la complexité GroupJoin, compatibilité du modèle mental entre SQL et LINQ…
Est-il facile de faire un LEFT JOIN en SQL :sql SELECT * FROM facebook LEFT JOIN linkedin ON facebook.name = linkedin.name Que diriez-vous de faire cela en C# et Entity Framework Core ? Avant EF Core 10, cette simple requête SQL devenait ceci dans LINQ :```csharp
var query = dbContext.Products
.GroupJoin(
dbContext.Reviews,
product => product.Id,
review => review.ProductId,
(product, reviewList) => new { product, subgroup = reviewList })
.SelectMany(
joinedSet => joinedSet.subgroup.DefaultIfEmpty(),
(joinedSet, review) => new { /* ... */ });
## Qu'est-ce que LEFT JOIN ? Une explication visuelle
La meilleure façon de comprendre LEFT JOIN est de commencer par un exemple concret.
### Notre exemple de scénario
Nous avons deux tableaux :
**Table Facebook (table de gauche)**
| Nom | #d'amis |
|--------------|--------------|
| Mat | 300 |
| Lisa | 500 |
| jeff | 600 |
| Sarah | 400 |
**Tableau LinkedIn (tableau de droite)**
| Nom | # de connexions |
|--------|------|
| Mat | 500 |
| Lisa | 200 |
| Sarah | 100 |
| Louis | 800 |
### Requête et logique SQL```sql
SELECT *
FROM facebook
LEFT JOIN linkedin ON facebook.name = linkedin.name
```Que dit cette requête ? "Donnez-moi **tous les enregistrements** dans la table `facebook`. S'il existe un enregistrement correspondant dans LinkedIn, ajoutez-le, sinon définissez les colonnes LinkedIn sur NULL."
### Exécution étape par étape
**Ligne 1 - Mat :**
- Sur Facebook : Matt (300 amis)
- Consultez LinkedIn → Trouvé Matt (500 connexions)
- ✅ Il y a une correspondance
- **Résultat :** `Matt | 300 | Matt | 500`
**Ligne 2 - Lisa :**
- Sur Facebook : Lisa (500 amis)
- Vérifier sur LinkedIn → Lisa trouvée (200 connexions)
- ✅ Il y a une correspondance
- **Résultat :** `Lisa | 500 | Lisa | 200`
**Ligne 3 - Jeff :**
- Sur Facebook : Jeff (600 amis)
- Vérifiez sur LinkedIn → Jeff introuvable ❌
- Règle LEFT JOIN : L'enregistrement du côté gauche est conservé !
- **Résultat :** `Jeff | 600 | NULL | NULL`
**Ligne 4 - Sarah :**
- Sur Facebook : Sarah (400 amis)
- Consultez LinkedIn → Sarah trouvée (100 connexions)
- ✅ Il y a une correspondance
- **Résultat :** `Sarah | 400 | Sarah | 100`
**Alors qu'est-il arrivé à Louis ?**
Louis n'est disponible que sur LinkedIn, pas sur Facebook. Parce que LEFT JOIN se concentre sur la **table de gauche**, Louis est finalement invisible. Nous devrons également utiliser FULL OUTER JOIN pour voir Louis.
### Tableau des résultats finaux
| facebook.Nom | facebook.Nombre d'amis | linkedin.Nom | linkedin.Nombre de connexions |
|--------------------|------------|---------------|-------------------------------|
| Mat | 300 | Mat | 500 |
| Lisa | 500 | Lisa | 200 |
| jeff | 600 | **NULL** | **NULL** |
| Sarah | 400 | Sarah | 100 |
### JOINTURE GAUCHE vs JOINTURE INTÉRIEUREQue se passerait-il si nous utilisions INNER JOIN ? La ligne Jeff **disparaîtrait** car INNER JOIN renvoie uniquement les enregistrements qui **sont des correspondances dans les deux tables**.
## Problème : « point douloureux » dans LINQ
### Ancienne méthode : GroupJoin + DefaultIfEmpty + SelectMany
Avant EF Core 10, nous devions utiliser une construction complexe pour effectuer un LEFT JOIN :
#### Syntaxe de requête```csharp
var query =
from product in dbContext.Products
join review in dbContext.Reviews
on product.Id equals review.ProductId
into reviewGroup
from subReview in reviewGroup.DefaultIfEmpty()
orderby product.Id, subReview.Id
select new
{
ProductId = product.Id,
product.Name,
product.Price,
ReviewId = (int?)subReview.Id ?? 0,
Rating = (int?)subReview.Rating ?? 0,
Comment = subReview.Comment ?? "N/A"
};
```Il y a trois points critiques dans ce code :
1. **`into reviewGroup`** → Convertit le JOIN standard en GroupJoin
2. **`reviewGroup.DefaultIfEmpty()`** → Remplit les groupes vides avec `[null]`
3. **`?? operatörü`** → Gère en toute sécurité les valeurs nulles
#### Syntaxe de la méthode```csharp
var query = dbContext.Products
.GroupJoin(
dbContext.Reviews,
product => product.Id,
review => review.ProductId,
(product, reviewList) => new { product, subgroup = reviewList })
.SelectMany(
joinedSet => joinedSet.subgroup.DefaultIfEmpty(),
(joinedSet, review) => new
{
ProductId = joinedSet.product.Id,
joinedSet.product.Name,
ReviewId = (int?)review?.Id ?? 0,
// ...
});
```### Conséquences de cette complexité
Ce « point douloureux » a causé trois problèmes sérieux :
#### 1. Requêtes incorrectes
Les développeurs pourraient mélanger l'ordre de `GroupJoin`, `DefaultIfEmpty` et `SelectMany` et obtenir les résultats INNER JOIN par erreur.
#### 2. Comportement d'évitement
C'était le problème critique : pour éviter cette complexité, les développeurs exécutaient **deux requêtes distinctes** :```csharp
// ❌ KÖTÜ: N+1 Sorgu Problemi
var products = db.Products.ToList(); // 1. sorgu
var reviews = db.Reviews
.Where(r => productIds.Contains(r.ProductId))
.ToList(); // 2. sorgu
// Sonra C# tarafında birleştirme...
```Il s'agit d'un désastre de performances appelé **problème de requête N+1**.
#### 3. Charge cognitive
Une opération déclarative en SQL (« dites ce que vous voulez ») devenait procédurale dans LINQ (« décrivez comment le faire »).
## Solution : Nouveau LeftJoin dans EF Core 10
### Simplicité révolutionnaire
Avec EF Core 10 on peut désormais écrire :```csharp
var query = dbContext.Products
.LeftJoin(
dbContext.Reviews, // Sağ tablo
product => product.Id, // Sol anahtar
review => review.ProductId, // Sağ anahtar
(product, review) => new // Sonuç projeksiyonu
{
ProductId = product.Id,
product.Name,
product.Price,
ReviewId = (int?)review?.Id ?? 0,
Rating = (int?)review?.Rating ?? 0,
Comment = review?.Comment ?? "N/A"
})
.OrderBy(x => x.ProductId)
.ThenBy(x => x.ReviewId);
```### Tableau de comparaison
| Fonctionnalité | Vieille route | Nouvelle route |
|---------|----------|--------------|
| **Opérateurs clés** | `GroupJoin()`, `SelectMany()`, `DefaultIfEmpty()` | `LeftJoin()` |
| **Complexité du code** | ⚠️ Haute - Combinaison précise de trois opérateurs | ✅ Faible – Méthode unique et ciblée |
| **Lisibilité** | ❌ L'intention « se perd dans le bruit » | ✅ Toute personne familiarisée avec SQL comprendra |
| **Intention du développeur** | "Grouper, null, aplatir..." | "Faites LEFT JOIN!" |
### Identité SQL générée
La bonne chose : les deux méthodes produisent le **même SQL optimisé** :```sql
SELECT
p."Id" AS "ProductId",
p."Name",
p."Price",
COALESCE(r."Id", 0) AS "ReviewId",
COALESCE(r."Rating", 0) AS "Rating",
COALESCE(r."Comment", 'N/A') AS "Comment"
FROM "Products" AS p
LEFT JOIN "Reviews" AS r ON p."Id" = r."ProductId"
ORDER BY p."Id", COALESCE(r."Id", 0)
```**À retenir :** Les performances n'ont jamais été un problème. Le problème était l’expérience du développeur et la qualité du code.
## RightJoin également ajouté (mais à utiliser avec précaution)
EF Core 10 ajoute également la méthode `RightJoin` :```csharp
var query = dbContext.Reviews
.RightJoin(dbContext.Products, ...);
```Cependant, RIGHT JOIN est plus difficile à comprendre cognitivement. Refactorisez votre requête pour toujours utiliser LEFT JOIN :
- au lieu de ❌ `A.RightJoin(B, ...)`
- ✅ Utilisez `B.LeftJoin(A, ...)`
## Une remarque importante : la syntaxe des requêtes n'a pas encore été mise à jour
EF Core 10 a ajouté la **méthode** `.LeftJoin()`, mais le langage C# n'a pas encore ajouté le **mot-clé** `left join`.
Cela signifie:```csharp
// ✅ ÇALIŞIR (Metot Sözdizimi)
dbContext.Products.LeftJoin(...)
// ❌ HENÜZ ÇALIŞMAZ (Sorgu Sözdizimi)
from p in products
left join r in reviews on p.Id equals r.ProductId
select ...
```### D'où ?
Parce que :
- `.LeftJoin()` est une **mise à jour du framework** (package EF Core)
- `left join` est une **mise à jour du langage** (compilateur C# - Roslyn)
Les mises à jour linguistiques sont plus lentes et il existe une forte demande de la part de la communauté.
## Conseils d'experts : meilleures pratiques
### 1. La protection NULL est obligatoire
Lorsque vous utilisez LEFT JOIN, l'objet de droite peut être `null` :```csharp
// ❌ HATA: NullReferenceException fırlatır
select new { Rating = review.Rating }
// ✅ DOĞRU: Null-conditional operatör
select new { Rating = review?.Rating }
// ✅ DAHA İYİ: Varsayılan değer
select new { Rating = review?.Rating ?? 0 }
```### 2. L'indexation est essentielle à la performance
Si vous utilisez LEFT JOIN, les clés de jointure doivent avoir des index :```csharp
// Migration'da:
migrationBuilder.CreateIndex(
name: "IX_Reviews_ProductId",
table: "Reviews",
column: "ProductId");
```**Sans index :** O(N×M) - Analyse complète de la table - Minutes
**Par index :** O(N×log M) - Recherche d'index - Millisecondes
### 3. Choisissez uniquement ce dont vous avez besoin```csharp
// ❌ KÖTÜ: Tüm sütunları çeker
.LeftJoin(..., (p, r) => new { p, r })
// ✅ İYİ: Sadece gerekli alanlar
.LeftJoin(..., (p, r) => new
{
p.Name,
Rating = r?.Rating ?? 0
})
```Cela réduit considérablement les E/S de la base de données, le trafic réseau et l'utilisation de la mémoire.
### 4. Planifiez la structure de votre requête
Avant d'utiliser LEFT JOIN, demandez-vous :
- **Quelle est ma table "principale" ?** → Mettez-la à gauche
- **Quelles sont mes données "associées" ?** → Mettez-les à droite
- **Les données associées sont-elles obligatoires pour chaque enregistrement ?**
- Non → REJOINDRE À GAUCHE ✅
- Oui → JOINTURE INTÉRIEURE
## Erreurs courantes
- **Oublier les vérifications nulles** : L'objet sur le côté droit peut être nul après LEFT JOIN, assurez-vous d'utiliser `?.` ou `??`
- **Manque d'index** : LEFT JOIN sans index sur les clés de jointure crée un désastre en termes de performances
- **Sélection des colonnes inutiles** : sélectionnez uniquement les champs obligatoires au lieu d'extraire toutes les colonnes (`p, r`)
- **Utilisation de RIGHT JOIN** : inversez la requête et utilisez LEFT JOIN au lieu de RIGHT JOIN
- **Retour à GroupJoin** : utilisation de l'ancienne méthode complexe lorsqu'il existe une nouvelle méthode `.LeftJoin()`
## Outils et ressources
- [Notes de version d'EF Core 10](https://learn.microsoft.com/ef/core/what-is-new/ef-core-10.0/whatsnew)
- [Documentation de base d'Entity Framework](https://learn.microsoft.com/ef/core/)
- [Documentation officielle LINQ LeftJoin](https://learn.microsoft.com/dotnet/api/)
- [Guide visuel des types SQL JOIN](https://www.sql-join.com/)
- [.NET 10 Quoi de neuf](https://learn.microsoft.com/dotnet/core/whats-new/dotnet-10)
## Comparaison des performances
Nouvel opérateur LeftJoin dans EF Core 10 :
- **Runtime** : Même SQL généré → Mêmes performances
- **Temps de développement** : codage 100 % plus rapide
- **Coût de maintenance** : Le temps nécessaire pour comprendre le code est passé de 10 minutes à 30 secondes
- **Taux d'erreur** : les erreurs dues à la confusion de GroupJoin sont réduites à zéro
## Un regard vers l'avenirBien plus qu'une simple mise à jour, les opérateurs `LeftJoin` et `RightJoin` dans EF Core 10 sont un triomphe de l'ergonomie des développeurs.
Cette mise à jour a fourni :
✅ **Combiné le modèle mental entre SQL et LINQ**
✅ **Augmentation de l'incitation à éviter le problème de requête N+1**
✅ **La lisibilité et la maintenabilité du code ont été plus faciles**
✅ **Erreurs réduits, productivité accrue**
### Dernier mot```csharp
// EF Core 9 ve öncesi
var query = products
.GroupJoin(reviews, ...)
.SelectMany(...);
// 🤔 "Bu... LEFT JOIN mı yapıyor?"
// EF Core 10
var query = products
.LeftJoin(reviews, ...);
// 😊 "Ah, LEFT JOIN!"
```**Le code correspond enfin au modèle mental.**
Avec ce changement, EF Core a permis aux développeurs d'écrire des applications plus rapides et plus performantes (en évitant le problème de requête N+1) avec moins d'erreurs. Il ne s'agit pas seulement d'une mise à jour de syntaxe, mais également d'une mise à jour ergonomique qui encourage les développeurs à écrire un code plus propre sans sacrifier les performances.
---
*Cet article est basé sur les mises à jour .NET 10 et EF Core 10. Les codes sont testés et prêts à être utilisés dans l'environnement de production.*
FAQ
Frequently asked questions
Que couvre la « Masterclass SQL to LINQ LEFT JOIN : EF Core 10 et Modern Data Access » ?
Découvrez l'opérateur révolutionnaire LeftJoin introduit par EF Core 10 : suppression de la complexité GroupJoin, compatibilité du modèle mental entre SQL et LINQ…
Quel est le principal point à retenir ?
Découvrez l'opérateur révolutionnaire LeftJoin introduit par EF Core 10 : suppression de la complexité GroupJoin, compatibilité du modèle mental entre SQL et LINQ…
À qui s’adresse cet article ?
Pour les ingénieurs et les responsables techniques qui mettent en œuvre les décisions en matière d'architecture logicielle, de livraison et de production.
Continuer la lecture
Continuer la lecture
Articles connexes
Comment fonctionne une tranche verticale de l’intérieur ?
Comment une tranche verticale circule-t-elle en interne, de la demande à la validation, du gestionnaire à l'agrégation, de l'événement de boîte d'envoi à…
Articles connexes
De CRUD (Créer, Lire, Mettre à jour, Supprimer) à CQRS (Command Query Responsibility Segregation) : le problème est le modèle, pas le code
Qu'est-ce que CQRS, quelle est la différence entre CRUD et CQRS et quand faut-il utiliser CQRS ? Un guide expliquant pourquoi un seul modèle ne suffit pas…
Articles connexes
Au revoir tailwind.config.js : qu'est-ce que Tailwind v4 change ?
Découvrez les changements révolutionnaires apportés par Tailwind CSS v4 : migration de la configuration JavaScript vers CSS, nouveau moteur Oxide, contenu…