Aller au contenu principal

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();
Comparaison LINQ avec Doctrine QueryBuilder et JPQL
// 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érateurDescriptionSQL
Where(condition)FiltrerWHERE
OrderBy(champ)Trier croissantORDER BY ASC
OrderByDescending(champ)Trier décroissantORDER BY DESC
Select(projection)Sélectionner des colonnesSELECT colonne
Take(n)Limiter le nombreLIMIT n
Skip(n)Sauter n enregistrementsOFFSET n
Count()CompterCOUNT(*)
FirstOrDefault()Premier ou nullLIMIT 1
Any(condition)ExistenceEXISTS

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();
SQL brut = dernier recours

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


Quelle méthode EF Core récupère tous les enregistrements d'une table de manière asynchrone ?


Quelle méthode cherche un enregistrement par sa clé primaire de manière optimisée ?


Quelle méthode LINQ filtre les articles selon une condition ?


Quelles méthodes LINQ combiner pour paginer (page 2, 10 articles par page) ?


Quelle méthode trie les articles du plus récent au plus ancien ?


Quelle méthode récupère le premier article correspondant à une condition, ou null si aucun ?


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)


Bonne pratique - Toujours trier les listes

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)


Bonne pratique - Paramètre int? nullable

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


Bonne pratique - Paginer dès le départ

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.

📌 Une solution