Fermer

avril 18, 2024

Notions de base d’ASP.NET Core : premiers pas avec LINQ

Notions de base d’ASP.NET Core : premiers pas avec LINQ


La manipulation des données est une tâche courante pour les développeurs ASP.NET Core, et LINQ est une fonctionnalité puissante qui vous permet d’écrire des requêtes directement dans la syntaxe du langage C#. Consultez cet article pour savoir comment commencer à utiliser LINQ dans des requêtes simples vers des scénarios plus complexes.

Créer une application Web peut être un défi, surtout pour les débutants. Pour simplifier les tâches courantes d’accès et de manipulation des données dans ce type d’application, les développeurs peuvent utiliser des ressources telles que LINQ, qui dispose de fonctions permettant une manipulation efficace des données.

Dans cet article, nous aborderons le processus de création d’une application simple à l’aide d’ASP.NET Core qui exploite la puissance de LINQ pour manipuler les données de manière simple et efficace. À la fin de ce didacticiel, vous aurez une solide compréhension de la façon de créer une application Web simple mais fonctionnelle en utilisant le meilleur de LINQ.

Qu’est-ce que LINQ ?

LINQ, abréviation de Language Integrated Query, est une fonctionnalité du langage en C# qui permet aux développeurs d’écrire des requêtes directement dans la syntaxe du langage. Dans le contexte d’ASP.NET Core, LINQ est devenu un outil précieux pour travailler avec des collections de données.

LINQ fournit un modèle cohérent pour interroger et manipuler les données, quelle que soit la source de données. Il permet aux développeurs d’écrire des requêtes en utilisant une syntaxe familière, rendant le code plus expressif et plus lisible. LINQ ne se limite pas à travailler avec des bases de données : il peut être utilisé avec diverses sources de données telles que des tableaux, des collections, XML et bien plus encore.

Dans ASP.NET Core, LINQ est couramment utilisé pour interroger des bases de données, en particulier avec Entity Framework Core, un framework de mappage objet-relationnel (ORM) populaire.

EF Core permet aux développeurs d’interagir avec des bases de données à l’aide d’objets C#, et LINQ fournit un moyen naturel et efficace d’interroger et de transformer ces données. Un autre avantage de LINQ est qu’il fait partie de l’espace de noms natif ASP.NET Core (System.Linq). Cela signifie que toutes ses ressources sont disponibles sans utiliser de bibliothèques tierces, recevant des mises à jour à chaque nouvelle version de .NET.

L’image ci-dessous montre comment il est possible d’optimiser la syntaxe C# en utilisant l’approche LINQ au lieu de l’approche traditionnelle.

Approche traditionnelle VS approche LINQ

Pratiquer LINQ dans une application ASP.NET Core

Pour nous entraîner à utiliser LINQ, nous allons créer une application simple utilisant SQLite comme base de données et EF Core comme ORM pour inscrire les étudiants. Nous verrons ensuite les principales ressources LINQ disponibles pour la manipulation des données.

Pour créer l’exemple d’application, vous devez disposer de la dernière version de .NET. Cet article utilise la version 8. Pour un IDE, cet article utilise Visual Studio Code. Il est également nécessaire d’avoir EF Core installé localement ; pour l’installer, exécutez simplement la commande dotnet tool install --global dotnet-ef dans la borne.

Vous pouvez accéder au code source complet ici : Code source du Centre de contact.

Ouvrez un terminal et exécutez les commandes suivantes pour créer l’application et installer les packages NuGet.

dotnet new web -o StudentHub

cd StudentHub

dotnet add package Microsoft.EntityFrameworkCore.Sqlite

dotnet add package Microsoft.EntityFrameworkCore.Design

dotnet add package Swashbuckle.AspNetCore

Créons maintenant des classes pour représenter les entités étudiant, cours et inscription. Créez un nouveau dossier appelé « Modèles » et créez-y les classes ci-dessous :

namespace StudentHub.Models;

public class Student
{
  public Guid Id { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public DateTime DateOfBirth { get; set; }
  public string Address { get; set; }
  public string PhoneNumber { get; set; }
  public string Email { get; set; }
  public string Gender { get; set; }
  public int Age { get; set; }
  public List<string> Courses { get; set; }
  public double Score { get; set; }
  
  public Student()
  {
  }
}
namespace StudentHub.Models;

public class Course
{
  public Guid CourseId { get; set; }
  public Guid CourseName { get; set; }
}
namespace StudentHub.Models;

public class Enrollment
{
  public Guid EnrollmentId { get; set; }
  public Guid StudentId { get; set; }
  public Guid CourseId { get; set; }
}

L’étape suivante consiste à créer la classe de contexte qui mettra en œuvre la connexion à la base de données et instanciera la liste des dossiers des étudiants. Alors, créez un dossier appelé « Data » et à l’intérieur, créez la classe ci-dessous :

using Microsoft.EntityFrameworkCore;
using StudentHub.Models;

namespace StudentHub.Data;

public class StudentDbContext : DbContext
{
  public DbSet<Student> Students { get; set; }
  public DbSet<Course> Courses { get; set; }
  public DbSet<Enrollment> Enrollments { get; set; }

  public StudentDbContext(DbContextOptions<StudentDbContext> options)
    : base(options)
  {
  }
}

Opérateurs de requête standard LINQ

Les opérateurs de requête standard LINQ sont des méthodes et des expressions qui vous permettent d’effectuer des opérations de requête sur des collections de données. Ces opérateurs sont utilisés pour filtrer, trier, regrouper et projeter des données dans les requêtes LINQ. Ils font partie intégrante du langage C# et des autres langages .NET prenant en charge LINQ.

Les opérateurs de requête standard sont divisés en plusieurs catégories, chacune effectuant une opération spécifique sur une séquence (collection) d’éléments.

Ensuite, nous apprendrons à connaître chacun des modèles et vérifierons un exemple pratique de chacun d’eux. Ne vous inquiétez pas du projet pour l’instant : à la fin de l’explication, nous implémenterons tout dans l’exemple de code.

1. Filtrage

Pour filtrer les éléments à l’aide de LINQ, nous utilisons la méthode d’extension « Où ». Exemple:

public IEnumerable<Student> GetMaleStudents()
{
  var result = from student in _db.Students
    where student.Gender == "Male"
    select student;
  
  return result;
}

Notez que dans ce code la variable « result » est créée pour stocker le résultat de la requête LINQ from student in _db.Students where student.Gender == "Male", qui filtre les étudiants pour inclure uniquement ceux dont l’attribut Genre est égal à « Homme ». Puis le code select student est déclaré, ce qui indique que la requête doit renvoyer l’objet étudiant pour chaque élément répondant aux critères spécifiés.

2. Projection

La projection fait référence à la capacité de transformer ou de sélectionner des propriétés spécifiques d’objets dans une séquence. Dans LINQ, la projection est principalement effectuée à l’aide de l’opérateur Select. L’objectif est de créer une nouvelle forme de données contenant uniquement les informations nécessaires à la tâche.

L’opérateur Select permet de spécifier la projection des données d’une collection vers une nouvelle composition.

public IEnumerable<string> GetStudentFullNames()
{
  var result = from student in _db.Students
select $"{student.FirstName} {student.LastName}";

  return result;
}

Le code ci-dessus crée une séquence de chaînes contenant les noms complets des étudiants, en sélectionnant uniquement les propriétés FirstName et LastName via LINQ. select opérateur.

3. Commande

L’ordre des éléments dans LINQ se fait à l’aide du OrderBy et OrderByDescending opérateurs, qui classent les éléments d’une séquence en fonction de critères spécifiques. Les deux opérateurs sont utilisés conjointement avec la clause select pour effectuer la projection des éléments ordonnés.

Commandé par:

L’opérateur OrderBy est utilisé pour trier les éléments d’une séquence par ordre croissant en fonction d’une clé spécifiée. La clé est généralement une propriété de l’objet ou une expression qui renvoie une valeur qui sera utilisée pour déterminer l’ordre.

public IEnumerable<Student> GetStudentsOrderedByName()
{
  var result = _db.Students.OrderBy(student => student.FirstName);

  return result;
}

Dans cet exemple, OrderBy(student => student.FirstName) trie les élèves par ordre croissant. Dans ce cas, il triera les étudiants par ordre alphabétique de A à Z.

Ordre par décroissant :

Le OrderByDescending l’opérateur fonctionne de la même manière que OrderBy mais trie les éléments par ordre décroissant.

public IEnumerable<Student> GetStudentsByDescendingName()
{
  var result = _db.Students.OrderByDescending(student => student.FirstName);

  return result;
}

Dans cet exemple, OrderByDescending(student => student.FirstName) trie les nombres par ordre décroissant.

Puis par:

Le ThenBy La méthode est utilisée dans LINQ pour effectuer un tri secondaire sur une séquence déjà triée. En d’autres termes, vous pouvez utiliser ThenBy pour spécifier un deuxième critère de classement lorsque les éléments ont la même valeur que le premier critère.

public IEnumerable<Student> GetStudentsOrderedByNameAndThenByAge()
{
  var result = _db.Students.OrderBy(student => student.FirstName).ThenBy(student => student.Age);

  return result;
}

Dans cet exemple, les étudiants sont d’abord classés par nom de famille (OrderBy(student => student.FirstName))puis, si deux élèves portent le même prénom, ils seront classés par âge (ThenBy(student => student.Age)).

4. Regroupement

L’opérateur de regroupement dans LINQ est représenté par le GroupBy méthode. Il est utilisé pour regrouper les éléments d’une séquence en fonction d’une clé spécifique. L’opération de regroupement crée des groupes d’éléments partageant la même clé. Exemple:

public IEnumerable<IGrouping<int, Student>> GroupStudentsByAge()
{
  var result = _db.Students.GroupBy(student => student.Age);

  return result;
}

Dans l’exemple ci-dessus, le GroupBy L’opérateur est utilisé pour regrouper les étudiants en fonction de leur âge. Il faut une expression lambda qui spécifie la clé de regroupement, dans ce cas student => student.Age.

Le GroupStudentsByAge La méthode, lorsqu’elle est appelée, renverra une séquence de groupes, où chaque groupe représente une tranche d’âge et contient une collection d’étudiants de cet âge.

GroupJoin:

Effectue une jointure entre deux séquences et regroupe les résultats.

public IEnumerable<IGrouping<string, Student>> GroupStudentsByCourses()
{
  return _db.Students
    .GroupJoin(
      _db.Enrollments,
      student => student.Id,
      enrollment => enrollment.StudentId,
      (student, enrollments) => new { student, enrollments }
    )
    .SelectMany(
      x => x.enrollments.DefaultIfEmpty(),
      (x, enrollment) => new { Student = x.student, Enrollment = enrollment }
    )
    .GroupBy(x => x.Enrollment.CourseId.ToString(), x => x.Student);
}

Pour rechercher: Convertit une chaîne en objet Lookup.

public ILookup<Guid, Student> ToLookupByStudentId()
{
  return _db.Students.ToLookup(student => student.Id);
}

5. Jonction

L’opération de jointure dans LINQ est effectuée à l’aide de l’opérateur de jointure. Il vous permet de combiner des éléments de deux séquences différentes en fonction d’une condition spécifiée, produisant une nouvelle séquence d’éléments correspondants. Exemple:

public IEnumerable<string> GetStudentCourseNames()
{
  var result = from student in _db.Students
    join enrollment in _db.Enrollments on student.Id equals enrollment.StudentId
    join course in _db.Courses on enrollment.CourseId equals course.CourseId
    select $"{student.FirstName} {student.LastName} - {course.CourseName}";
  return result;
}

Le GetStudentCourseNames La méthode utilise l’opération de jointure entre trois tables : Étudiants, Inscriptions et Cours. L’objectif est d’obtenir une séquence de chaînes qui représentent les noms des étudiants et les noms des cours dans lesquels ils sont inscrits. Il s’agit d’un moyen efficace d’obtenir des données associées à partir de plusieurs tables dans une seule requête LINQ.

6. Agrégation

Dans LINQ, l’agrégation fait référence à l’application d’opérations qui combinent des éléments d’une séquence en une seule valeur. Les opérateurs d’agrégation sont utilisés pour effectuer des calculs sur une séquence, tels que l’addition, le comptage, la recherche du minimum ou du maximum, le calcul de la moyenne, etc. Certains des opérateurs d’agrégation les plus courants dans LINQ incluent Count, Sum, Min, Max et Average.

Exemple:

var numbers = new List<int> { 1, 2, 3, 4, 5 };

var sum = numbers.Sum(); 
var count = numbers.Count(); 
var minimum = numbers.Min(); 
var maximum = numbers.Max(); 
var average = numbers.Average(); 

7. Partitionnement

La catégorie « Partitionnement » dans LINQ fait référence aux opérateurs qui vous permettent de diviser une séquence en partitions plus petites. Le principal opérateur de cette catégorie est Skip and Take.

Prendre:

Renvoie un nombre spécifié d’éléments depuis le début d’une séquence.

Exemple:

public IEnumerable<Student> GetFirstTwoStudents()
{
  var result = _db.Students.Take(2);

  return result;
}

Sauter:

Ignore un nombre spécifié d’éléments au début d’une séquence et renvoie les éléments restants.

Exemple:

public IEnumerable<Student> GetStudentsAfterSkippingFirstTwo()
{
  var result = _db.Students.Skip(2);

  return result;
}

8. Opérateurs de filtrage supplémentaires

Il existe des opérateurs de filtrage supplémentaires tels que OfType et Distinct.

DeType :

Filtre les éléments d’une séquence pour inclure uniquement ceux d’un certain type.

public IEnumerable<Student> FilterStudentsByType()
{
  return _db.Students.OfType<Student>();
}

Distinct:

Renvoie des éléments distincts d’une séquence.

public IEnumerable<string> GetDistinctCourses()
{
  return _db.Students
    .AsEnumerable()
    .SelectMany(student => student.Courses)
    .Distinct();
}

9. Définir les opérateurs

Les opérateurs d’ensemble dans LINQ effectuent des opérations entre des ensembles d’éléments, tels que l’union, l’intersection et la différence. Ils sont particulièrement utiles lorsque vous travaillez avec deux séquences ou plus et que vous souhaitez effectuer des opérations impliquant de combiner ou de comparer des éléments entre elles.

Syndicat:

Renvoie l’union de deux séquences.

public IEnumerable<string> UnionStudentNames(IEnumerable<Student> firstList, IEnumerable<Student> secondList)
{
  var unionList = firstList.Union(secondList);
  return unionList.Select(student => $"{student.FirstName} {student.LastName}");
}

Couper:

Renvoie l’intersection de deux séquences.

public IEnumerable<string> IntersectStudentNames(IEnumerable<Student> firstList, IEnumerable<Student> secondList)
{
  var intersectList = firstList.Intersect(secondList);
  return intersectList.Select(student => $"{student.FirstName} {student.LastName}");
}

Sauf:

Renvoie les éléments qui se trouvent dans la première séquence mais pas dans la seconde.

public IEnumerable<string> ExceptStudentNames(IEnumerable<Student> firstList, IEnumerable<Student> secondList)
{
  var exceptList = firstList.Except(secondList);
  return exceptList.Select(student => $"{student.FirstName} {student.LastName}");
}

10. Opérateurs de quantification

Les opérateurs de quantification dans LINQ sont utilisés pour évaluer les conditions concernant tout ou partie des éléments d’une séquence. Il existe deux opérateurs principaux dans cette catégorie : All et Any.

Tous:

Vérifie si tous les éléments remplissent une condition.

public bool CheckIfAllStudentsPassed()
{
  return _db.Students.All(student => student.Score >= 60);
}

N’importe lequel:

Vérifie si au moins un élément remplit une condition.

public bool CheckIfAnyStudentFailed()
{
  return _db.Students.Any(student => student.Score < 60);
}

Poursuite de l’exemple d’application

Il s’agissait des principaux opérateurs de requête standard LINQ. Maintenant que nous avons vu un exemple de chacun, implémentons-les dans l’application et créons des points de terminaison pour y accéder.

Créez un nouveau dossier appelé « Services » et à l’intérieur, créez la classe ci-dessous :

using StudentHub.Data;
using StudentHub.Models;

namespace StudentHub.Services;
public class StudentService
{
  private readonly StudentDbContext _db;

  public StudentService(StudentDbContext db)
  {
    _db = db;
  }

  public async Task CreateStudent(Student student)
  {
    _db.Students.Add(student);
    await _db.SaveChangesAsync();
  }

  
  public IEnumerable<Student> GetMaleStudents()
  {
    var result = from student in _db.Students
      where student.Gender == "Male"
      select student;

    return result;
  }

  public IEnumerable<Student> GetFemaleStudents()
  {
    var result = from student in _db.Students
      where student.Gender == "Female"
      select student;
   
    return result;
  }

  public IEnumerable<Student> GetOthersStudents()
  {
    var result = from student in _db.Students
      where student.Gender == "Others"
      select student;

    return result;
  }
  
  
  public IEnumerable<Student> GetMaleStudentsOnly()
  {
    var result = _db.Students.OfType<Student>().Where(s => s.Gender == "Male");

    return result;
  }

  public IEnumerable<Student> GetFemaleStudentsOnly()
  {
    var result = _db.Students.OfType<Student>().Where(s => s.Gender == "Female");

    return result;
  }

  public IEnumerable<Student> GetOthersStudentsOnly()
  {
    var result = _db.Students.OfType<Student>().Where(s => s.Gender == "Others");

    return result;
  }

  
  public IEnumerable<string> GetStudentFullNames()
  {
    var result = from student in _db.Students
      select $"{student.FirstName} {student.LastName}";

    return result;
  }

  
  public IEnumerable<string> GetCoursesForAllStudents()
  {
    var result = _db.Students
      .AsEnumerable()
      .SelectMany(student => student.Courses)
      .ToList();

    return result;
  }

  
  public IEnumerable<Student> GetFirstTwoStudents()
  {
    var result = _db.Students.Take(2);

    return result;
  }

  
  public IEnumerable<Student> GetStudentsAfterSkippingFirstTwo()
  {
    var result = _db.Students.Skip(2);

    return result;
  }

  
  public IEnumerable<Student> GetStudentsOrderedByName()
  {
    var result = _db.Students.OrderBy(student => student.FirstName);

    return result;
  }

  
  public IEnumerable<Student> GetStudentsByDescendingName()
  {
    var result = _db.Students.OrderByDescending(student => student.FirstName);

    return result;
  }

  
  public IEnumerable<Student> GetStudentsOrderedByNameAndThenByAge()
  {
    var result = _db.Students.OrderBy(student => student.FirstName).ThenBy(student => student.Age);

    return result;
  }

  
  public IEnumerable<Student> GetStudentsReversed()
  {
    var result = _db.Students
      .AsEnumerable()
      .Reverse();

    return result;
  }

  
  public IEnumerable<IGrouping<int, Student>> GroupStudentsByAge()
  {
    var result = _db.Students.GroupBy(student => student.Age);

    return result;
  }

  public IEnumerable<IGrouping<string, Student>> GroupStudentsByCourses()
  {
    return _db.Students
      .GroupJoin(
        _db.Enrollments,
        student => student.Id,
        enrollment => enrollment.StudentId,
        (student, enrollments) => new { student, enrollments }
      )
      .SelectMany(
        x => x.enrollments.DefaultIfEmpty(),
        (x, enrollment) => new { Student = x.student, Enrollment = enrollment }
      )
      .GroupBy(x => x.Enrollment.CourseId.ToString(), x => x.Student);
  }

  public ILookup<Guid, Student> ToLookupByStudentId()
  {
    return _db.Students.ToLookup(student => student.Id);
  }

  
  public IEnumerable<string> GetStudentCourseNames()
  {
    var result = from student in _db.Students
      join enrollment in _db.Enrollments on student.Id equals enrollment.StudentId
      join course in _db.Courses on enrollment.CourseId equals course.CourseId
      select $"{student.FirstName} {student.LastName} - {course.CourseName}";

    return result;
  }

  
  public Student[] ConvertToStudentArray()
  {
    var result = _db.Students.ToArray();

    return result;
  }

  
  public Student GetFirstStudent()
  {
    var result = _db.Students.First();

    return result;
  }

  
  public double GetAverageScore()
  {
    var result = _db.Students.Average(student => student.Score);

    return result;
  }

  
  public IEnumerable<Student> FilterStudentsByType()
  {
    return _db.Students.OfType<Student>();
  }

  public IEnumerable<string> GetDistinctCourses()
  {
    return _db.Students
      .AsEnumerable()
      .SelectMany(student => student.Courses).Distinct();
  }

  
  public IEnumerable<string> UnionStudentNames(IEnumerable<Student> firstList, IEnumerable<Student> secondList)
  {
    var unionList = firstList.Union(secondList);
    return unionList.Select(student => $"{student.FirstName} {student.LastName}");
  }

  public IEnumerable<string> IntersectStudentNames(IEnumerable<Student> firstList, IEnumerable<Student> secondList)
  {
    var intersectList = firstList.Intersect(secondList);
    return intersectList.Select(student => $"{student.FirstName} {student.LastName}");
  }

  public IEnumerable<string> ExceptStudentNames(IEnumerable<Student> firstList, IEnumerable<Student> secondList)
  {
    var exceptList = firstList.Except(secondList);
    return exceptList.Select(student => $"{student.FirstName} {student.LastName}");
  }

  
  public bool CheckIfAllStudentsPassed()
  {
    return _db.Students.All(student => student.Score >= 60);
  }

  public bool CheckIfAnyStudentFailed()
  {
    return _db.Students.Any(student => student.Score < 60);
  }
}

Le code ci-dessus contient toutes les méthodes évoquées précédemment.

Créons maintenant les points de terminaison qui appelleront ces méthodes, en plus des configurations d’injection de dépendances. Pour ce faire, remplacez le code existant dans le fichier Program.cs par le code ci-dessous :

using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi.Models;
using StudentHub.Data;
using StudentHub.Models;
using StudentHub.Services;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<StudentDbContext>(options =>
{
  options.UseSqlite("Data Source=students_db.db");
});
builder.Services.AddTransient<StudentService>();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
  c.SwaggerDoc("v1", new OpenApiInfo { Title = "StudentHub", Version = "v1" });
});

var app = builder.Build();

app.UseSwagger();
app.UseSwaggerUI(c =>
{
  c.SwaggerEndpoint("/swagger/v1/swagger.json", "StudentHub API V1");
  c.RoutePrefix = string.Empty;
});


app.MapPost("/api/students", async (Student student, StudentService studentService) =>
{
  await studentService.CreateStudent(student);
  return Results.Ok();
});

app.MapGet("/api/students/male", (StudentService studentService) => studentService.GetMaleStudents());

app.MapGet("/api/students/female", (StudentService studentService) => studentService.GetFemaleStudents());

app.MapGet("/api/students/others", (StudentService studentService) => studentService.GetOthersStudents());

app.MapGet("/api/students/male-only", (StudentService studentService) => studentService.GetMaleStudentsOnly());

app.MapGet("/api/students/female-only", (StudentService studentService) => studentService.GetFemaleStudentsOnly());

app.MapGet("/api/students/others-only", (StudentService studentService) => studentService.GetOthersStudentsOnly());

app.MapGet("/api/students/full-names", (StudentService studentService) => studentService.GetStudentFullNames());

app.MapGet("/api/students/courses", (StudentService studentService) => studentService.GetCoursesForAllStudents());

app.MapGet("/api/students/first-two", (StudentService studentService) => studentService.GetFirstTwoStudents());

app.MapGet("/api/students/ordered-by-name", (StudentService studentService) => studentService.GetStudentsOrderedByName());

app.MapGet("/api/students/ordered-by-name-age", (StudentService studentService) => studentService.GetStudentsOrderedByNameAndThenByAge());

app.MapGet("/api/students/reversed", (StudentService studentService) => studentService.GetStudentsReversed());

app.MapGet("/api/students/grouped-by-age", (StudentService studentService) => studentService.GroupStudentsByAge());

app.MapGet("/api/students/to-array", (StudentService studentService) => studentService.ConvertToStudentArray());

app.MapGet("/api/students/first", (StudentService studentService) => studentService.GetFirstStudent());

app.MapGet("/api/students/average-score", (StudentService studentService) => studentService.GetAverageScore());

app.MapGet("/api/students/filterByType", (StudentService studentService) => studentService.FilterStudentsByType());

app.MapGet("/api/students/distinctCourses", (StudentService studentService) => studentService.GetDistinctCourses());

app.MapGet("/api/students/unionNames", (StudentService studentService, IEnumerable<Student> firstList, IEnumerable<Student> secondList) => studentService.UnionStudentNames(firstList, secondList));

app.MapGet("/api/students/intersectNames", (StudentService studentService, IEnumerable<Student> firstList, IEnumerable<Student> secondList) => studentService.IntersectStudentNames(firstList, secondList));

app.MapGet("/api/students/exceptNames", (StudentService studentService, IEnumerable<Student> firstList, IEnumerable<Student> secondList) => studentService.ExceptStudentNames(firstList, secondList));

app.MapGet("/api/students/allPassed", (StudentService studentService) => studentService.CheckIfAllStudentsPassed());

app.MapGet("/api/students/anyFailed", (StudentService studentService) => studentService.CheckIfAnyStudentFailed());

app.MapGet("/api/students/groupByCourses", (StudentService studentService) => studentService.GroupStudentsByCourses());

app.MapGet("/api/students/toLookupByStudentId", (StudentService studentService) => studentService.ToLookupByStudentId());

app.MapGet("/api/students/studentCourseNames", (StudentService studentService) => studentService.GetStudentCourseNames());

app.MapGet("/api/students/descendingNames", (StudentService studentService) => studentService.GetStudentsByDescendingName());

app.MapGet("/api/students/skipFirstTwo", (StudentService studentService) => studentService.GetStudentsAfterSkippingFirstTwo());

app.Run();

Notre candidature est presque prête. Nous devons encore exécuter les commandes de migration EF Core pour générer la base de données et les tables. Ouvrez un terminal dans l’application et exécutez les commandes suivantes.

  1. dotnet ef migrations add InitialCreate

  2. dotnet ef database update

Enfin, nous sommes prêts à tester les fonctions LINQ. Pour ce faire, lancez simplement l’application avec la commande dotnet run et accédez à l’interface Swagger dans le navigateur : http://localhost:PORT/index.html.

Ensuite, nous pouvons effectuer certaines opérations comme indiqué dans le GIF ci-dessous :

Application en cours d'exécution

Considérations lors de l’utilisation de LINQ

LINQ est une extension puissante du langage C# qui permet des requêtes intégrées sur des collections de données et est souvent utilisée pour les requêtes de base de données avec Entity Framework. Bien que LINQ offre de nombreux avantages, il existe également certains inconvénients à prendre en compte :

Performance:

Dans certaines situations, les requêtes LINQ peuvent donner lieu à des requêtes SQL moins optimisées que les requêtes SQL manuelles écrites par un développeur expérimenté. Cela peut entraîner une baisse des performances sur les requêtes complexes ou lourdes.

Complexité de compréhension :

Pour les développeurs moins expérimentés, la syntaxe LINQ peut être plus complexe à comprendre que l’écriture de requêtes SQL traditionnelles. Selon le scénario, les requêtes LINQ peuvent augmenter la courbe d’apprentissage et rendre la maintenance du code difficile.

Limites d’expressivité :

Bien que LINQ soit assez expressif, il peut arriver que la syntaxe LINQ ne soit pas suffisamment flexible pour exprimer des requêtes complexes ou spécifiques. Dans de telles situations, les développeurs devront peut-être recourir à des requêtes SQL traditionnelles.

Difficulté de débogage :

Le débogage des requêtes LINQ peut être plus difficile que le débogage du code C# traditionnel ou des requêtes SQL. L’affichage et l’inspection des requêtes LINQ pendant le débogage peuvent ne pas être aussi intuitifs que l’examen direct des requêtes SQL.

Limites des performances de la mémoire :

Dans certains cas, notamment lorsqu’il s’agit de grands ensembles de données en mémoire, l’utilisation de LINQ peut entraîner une consommation excessive de ressources et affecter les performances des applications.

Compatibilité avec des bases de données spécifiques :

Certaines fonctionnalités spécifiques de la base de données peuvent ne pas être entièrement prises en charge par LINQ. Dans certains cas, il peut être nécessaire de recourir à des requêtes SQL directes.

Conclusion

Il est important de souligner que, malgré ces inconvénients, LINQ offre de nombreux avantages, comme une meilleure lisibilité du code, une plus grande productivité et la possibilité d’écrire des requêtes de manière plus sécurisée. Le choix entre l’utilisation de requêtes directes LINQ et SQL dépendra des besoins spécifiques du projet et des préférences de l’équipe de développement.

Dans cet article, nous avons appris les principales méthodes de requête LINQ avec des exemples simples et plus complexes. Malgré les considérations ci-dessus, envisagez toujours d’utiliser LINQ pour augmenter votre productivité lorsque vous travaillez avec une base de données.




Source link