Lire des données
Notions théoriques
Lire tous les enregistrements
Pour récupérer tous les articles de la base de données :
// Récupère tous les articles (équivalent SELECT * FROM articles)
var articles = await _context.Articles.ToListAsync();
Trouver un enregistrement par sa clé primaire
// Cherche par clé primaire (optimisé — utilise le cache EF si disponible)
var article = await _context.Articles.FindAsync(id);
// Retourne null si l'article n'existe pas
if (article == null)
{
return NotFound();
}
Chercher avec une condition (Where + FirstOrDefaultAsync)
// Récupère le premier article dont le titre contient "ASP.NET", ou null
var article = await _context.Articles
.FirstOrDefaultAsync(a => a.Titre.Contains("ASP.NET"));
// Tous les articles publiés, triés par date décroissante
var articlesPublies = await _context.Articles
.Where(a => a.EstPublie == true)
.OrderByDescending(a => a.DateCreation)
.ToListAsync();
LINQ — Language Integrated Query
LINQ est la syntaxe C# pour interroger des collections. EF Core traduit les requêtes LINQ en SQL :
// LINQ méthode (recommandé)
var articles = await _context.Articles
.Where(a => a.EstPublie) // WHERE est_publie = 1
.OrderByDescending(a => a.DateCreation) // ORDER BY date_creation DESC
.Select(a => new { a.Id, a.Titre, a.DateCreation }) // SELECT id, titre, date_creation
.Take(10) // LIMIT 10
.ToListAsync();
// Doctrine QueryBuilder (Symfony)
$articles = $em->getRepository(Article::class)
->createQueryBuilder('a')
->where('a.estPublie = true')
->orderBy('a.dateCreation', 'DESC')
->setMaxResults(10)
->getQuery()->getResult();
// JPQL (Spring Boot)
@Query("SELECT a FROM Article a WHERE a.estPublie = true ORDER BY a.dateCreation DESC")
List<Article> findPublished(Pageable pageable);
// LINQ EF Core (ASP.NET Core)
_context.Articles
.Where(a => a.EstPublie)
.OrderByDescending(a => a.DateCreation)
.Take(10)
.ToListAsync();
Opérateurs LINQ courants
| Opérateur | Description | SQL |
|---|---|---|
Where(condition) | Filtrer | WHERE |
OrderBy(champ) | Trier croissant | ORDER BY ASC |
OrderByDescending(champ) | Trier décroissant | ORDER BY DESC |
Select(projection) | Sélectionner des colonnes | SELECT colonne |
Take(n) | Limiter le nombre | LIMIT n |
Skip(n) | Sauter n enregistrements | OFFSET n |
Count() | Compter | COUNT(*) |
FirstOrDefault() | Premier ou null | LIMIT 1 |
Any(condition) | Existence | EXISTS |
Pagination avec Skip et Take
// Page 2 avec 10 articles par page
int page = 2;
int pageSize = 10;
var articles = await _context.Articles
.OrderByDescending(a => a.DateCreation)
.Skip((page - 1) * pageSize) // OFFSET 10
.Take(pageSize) // LIMIT 10
.ToListAsync();
Requête SQL brute (cas exceptionnel)
Pour les cas complexes impossibles avec LINQ :
// SQL brut (à utiliser avec parcimonie)
var articles = await _context.Articles
.FromSqlRaw("SELECT * FROM articles WHERE YEAR(date_creation) = {0}", 2024)
.ToListAsync();
Préférez toujours LINQ qui est typé et protégé contre les injections SQL. Le SQL brut est utile uniquement pour des requêtes très spécifiques ou des optimisations de performance.
Exemple pratique
Contrôleur avec plusieurs types de lectures :
// Controllers/ArticlesController.cs (actions de lecture)
// GET /Articles — Liste avec filtre et tri
public async Task<IActionResult> Index()
{
var articles = await _context.Articles
.Where(a => a.EstPublie)
.OrderByDescending(a => a.DateCreation)
.ToListAsync();
return View(articles);
}
// GET /Articles/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var article = await _context.Articles
.FirstOrDefaultAsync(a => a.Id == id);
if (article == null)
{
return NotFound();
}
return View(article);
}
// GET /Articles/Search?q=asp.net
public async Task<IActionResult> Search(string q)
{
if (string.IsNullOrWhiteSpace(q))
{
return RedirectToAction(nameof(Index));
}
var articles = await _context.Articles
.Where(a => a.Titre.Contains(q) || a.Contenu.Contains(q))
.OrderByDescending(a => a.DateCreation)
.ToListAsync();
ViewBag.SearchQuery = q;
return View("Index", articles);
}
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Vous allez implémenter les actions de lecture dans ArticlesController pour afficher la liste et le détail d'un article.
Étape 1 — Lire tous les articles publiés (action Index)
Sans OrderBy, l'ordre des résultats est indéterminé (dépend de l'ordre d'insertion ou de l'index utilisé par MySQL). Triez toujours les listes affichées à l'utilisateur pour garantir un affichage cohérent et prévisible.
Étape 2 — Lire un article par son Id (action Details)
Déclarez le paramètre id comme int? (nullable) plutôt que int. Cela permet de détecter le cas où l'URL /Articles/Details est appelée sans id (id sera null) et de retourner un 404 clair plutôt qu'une exception.
Étape 3 — Pagination de la liste
Ne jamais charger toutes les données d'une table si l'utilisateur n'en voit qu'une partie. Skip().Take() génère un LIMIT ... OFFSET ... SQL : seules les lignes nécessaires sont chargées en mémoire. Sans pagination, une table avec 10 000 articles rendrait votre application très lente.