You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mchsamples-.net-core/p08_BDD_EntityFramework/ex_042_001_EF_CF_conventions
Marc CHEVALDONNE a773557095
continuous-integration/drone/push Build is failing Details
update to .NET6
2 years ago
..
Nounours.cs added ex_042_006 et ex_042_007 5 years ago
NounoursDBEntities.cs minor fixes and read me 5 years ago
Program.cs added samples ex_042_001 5 years ago
ReadMe.md minor fixes and read me 5 years ago
ex_042_001_EF_CF_conventions.csproj update to .NET6 2 years ago

ReadMe.md

ex_042_001_EF_CF_conventions

02/01/2020 ⋅ Marc Chevaldonné


Le lien entre une base de données et vos classes à l'aide de Entity Framework Core se fait via une classe dérivant de DbContext. Cette classe doit contenir des DbSet<T>. Chaque DbSet<T> correspond à une table et T correspond à une de vos classes qu'on appelle entité. Le lien entre les tables et les entités est géré plus ou moins automatiquement par le framework.
EF Core permet de lire/écrire les instances d'entité de la base de données ; permet de créer des tables pour les entités via les migrations (pour les bases de données relationnelles) ; les types exposés dans les propriétés d'une entité deviennent automatiquement des entités (mais pas forcément des tables)

Entity Framework Core propose 3 solutions différentes pour relier des entités à des tables de la base de données :

  • conventions d'écriture : c'est la solution la plus simple, qui analyse le code de votre classe pour en déduire de quelle manière la relier à la table.
  • data annotations : elle se base sur des décorateurs (appelés data annotations) que vous placez autour de vos propriétés pour indiquer de quelle manière les relier aux colonnes de votre table. Les data annotations écrasent les conventions d'écriture.
  • Fluent API : directement dans le code de votre DbContext (plus précisément, dans la méthode OnModelCreating), vous précisez comment se fait le mapping entre votre entité et votre table. La Fluent API écrase les conventions d'écriture et les data annotations.

En d'autres termes, si vous n'écrivez rien, EF Core utilise les conventions d'écriture ; si vous n'utilisez que des data annotations, elles sont prioritaires sur les convetions d'écriture ; si vous utilisez la Fluent API, elle est prioritaire sur les deux autres méthodes. Mais on peut faire un mix des différentes méthodes.

Cet exemple montre de quelle manière les conventions d'écriture sont utilisées pour transformer une entité en table. Il montre notamment :

  • comment le nom de la table est choisi
  • s'il est possible d'ignorer une propriété de l'entité
  • comment le nom et le type d'une colonne de la table sont choisis
  • comment un identifiant unique est choisi et généré.

Cet exemple est répété d'une manière très similaire en utilisant les autres méthodes de mapping entre entité et table :

  • ex_042_002_EF_CF_data_annotations : avec les data annotations
  • ex_042_003_EF_CF_Fluent_API : avec la Fluent API

Comment est construit cet exemple ?

  • Le projet est de type .NET Core
  • Il contient deux classes :
    • Nounours
    • NounoursDBEntities

La classe NounoursDBEntities

  • Cette classe dérive de DbContext. Elle contient des DbSet<T>T est une entité. Elle contient autant de DbSet<T> que de tables.
class NounoursDBEntities : DbContext
{
    public DbSet<Nounours> NounoursSet { get; set; }
}

ici, on indique donc qu'il y aura une table de Nounours.

  • EF Core utilisera cette classe pour faire la création de la base de données et de ses tables. Pour cela, elle utilise la chaîne de connexion donnée dans la méthode OnConfiguring.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ex_042_001_EF_CF_conventions.Nounours.mdf;Trusted_Connection=True;");
}

=> cf ex_041_001_ConnectionStrings pour en savoir plus sur les chaîne de connexion

  • Dans cet exemple, la table de Nounours est créée en utilisant les conventions d'écriture de la classe Nounours.

La classe Nounours

  • Nounours est une entité, on parle aussi de classe POCO, i.e. Plain Old CLR Object.
public class Nounours
{
    public int ID
    {
        get; set;
    }

    public string Nom
    {
        get;
        set;
    }

    public DateTime DateDeNaissance
    {
        get;
        set;
    }

    public int NbPoils
    {
        get;
        set;
    }
}
  • Elle contient 3 propriétés en lecture/écriture : Nom, DateDeNaissance et NbPoils. Nous parlerons de la 4ème (ID) dans un moment.
  • Entity Framework Core va utiliser la classe POCO Nounours pour créer une table dans la base de données, lorsque le DbSet va être créé.
  • L'utilisation des conventions d'écriture d'Entity Framework font que la table qui va être créée aura :
    • un nom correspondant au nom de la classe POCO : ici "Nounours"
    • une colonne pour chaque propriété publique : ici, "Nom", "DateDeNaissance" et "NbPoils"
  • De plus, en rajoutant une propriété de type int et avec le nom "ID", Entity Framework ajoute directement une colonne "ID" et l'utilise comme clé primaire.

En résumé :

  • le nom de la table est choisi automatiquement (c'est le nom de l'entité)
  • toutes les propriétés ayant un getter et un setter publiques sont des colonnes de la table
  • le nom des colonnes est choisi automatiquement (il s'agit du nom des propriétés)
  • il n'est pas possible d'ignorer une propriété
  • le type d'une colonne est imposé par un mapping automatique entre les types .NET et ceux de la base de données. Par exemple :
    • un DateTime est transformé en datetime2(7)
    • un string est transformé en nvarchar(max)
    • si c'est une clé, elle est transformée en nvarchar(450)
    • ...
  • si la classe possède une propriété de type int s'appelant ID, elle est automatiquement utilisée comme clé primaire générée par lz base de données lors de l'insertion

La classe Program

Cette classe est le point d'entrée du programme :

  • Elle crée des instances de Nounours
Nounours chewie = new Nounours { Nom = "Chewbacca", DateDeNaissance = new DateTime(1977, 5, 27), NbPoils = 1234567 };
Nounours yoda = new Nounours { Nom = "Yoda", DateDeNaissance = new DateTime(1980, 5, 21), NbPoils = 3 };
Nounours ewok = new Nounours { Nom = "Ewok", DateDeNaissance = new DateTime(1983, 5, 25), NbPoils = 3456789 };
  • Elle démarre une connexion à la base de données
using (NounoursDBEntities db = new NounoursDBEntities())
{
//...
}
  • Elle vérifie si la table est vide, et si ce n'est pas le cas, elle la vide.
    Notez l'accès à la table de Nounours via db.NounoursSet.
    Notez également que tant que SaveChanges n'est pas appelée, les suppressions ne sont pas effectives dans la base, seulement en local dans le programme.
    Cette partie de l'exemple ne s'exécutera que si la base existe déjà, par exemple lors d'une deuxième exécution.
if (db.NounoursSet.Count() > 0)
{
    WriteLine("La base n'est pas vide !");
    foreach (var n in db.NounoursSet)
    {
        WriteLine($"\t{n}");
    }
    WriteLine("début du nettoyage...");

    foreach (var n in db.NounoursSet.ToArray())
    {
        WriteLine($"Suppression de {n}");
        db.NounoursSet.Remove(n);
    }

    WriteLine("Base avant sauvegarde des changements :");
    foreach (var n in db.NounoursSet)
    {
        WriteLine($"\t{n}");
    }
    db.SaveChanges();
    WriteLine("Base après sauvegarde des changements :");
    foreach (var n in db.NounoursSet)
    {
        WriteLine($"\t{n}");
    }
}
  • Elle ajoute ensuite les Nounourset sauvegarde les changements pour que ceux-ci soit effectivement ajoutés à la base.
db.NounoursSet.AddRange(new Nounours[] { chewie, yoda, ewok });

db.SaveChanges();
WriteLine("Base après ajout des 3 nounours et sauvegarde des changements :");
foreach (var n in db.NounoursSet)
{
    WriteLine($"\t{n}");
}

Comment exécuter cet exemple ?

Pour tester cette application, n'oubliez pas les commandes comme présentées dans l'exemple ex_041_001 : pour générer l'exemple, il vous faut d'abord préparer les migrations et les tables.

  • Ouvrez la Console du Gestionnaire de package, pour cela, dirigez-vous dans le menu Outils, puis Gestionnaire de package NuGet, puis Console du Gestionnaire de package.
  • Dans la console que vous venez d'ouvrir, déplacez-vous dans le dossier du projet .NET Core, ici :
cd .\p08_BDD_EntityFramework\ex_042_001_EF_CF_conventions

Note: si vous n'avez pas installé correctement EntityFrameworkCore, il vous faudra peut-être utiliser également :

  • dotnet tool install --global dotnet-ef si vous utilisez la dernière version de .NET Core (3.1 aujourd'hui),

  • dotnet tool install --global dotnet-ef --version 3.0.0 si vous vous utiliser spécifiquement .NET Core 3.0.

    • Migration :
dotnet ef migrations add migration_ex_042_001
  • Création de la table :
dotnet ef database update
  • Génération et exécution Vous pouvez maintenant générer et exécuter l'exemple ex_042_001_EF_CF_conventions.

  • Le résultat de l'exécution doit ressembler à :

Base après ajout des 3 nounours et sauvegarde des changements :
      1: Chewbacca (27/05/1977, 1234567 poils)
      2: Yoda (21/05/1980, 3 poils)
      3: Ewok (25/05/1983, 3456789 poils)

Note : les identifiants peuvent varier en fonction du nombre d'exécutions

  • Comment vérifier le contenu des bases de données SQL Server ? Vous pouvez vérifier le contenu de votre base en utilisant l'Explorateur d'objets SQL Server.

  • Pour cela, allez dans le menu Affichage puis Explorateur d'objets SQL Server.

  • Déployez dans l'Explorateur d'objets SQL Server :

    • SQL Server,

    • puis (localdb)\MSSQLLocalDB ...,

    • puis Bases de données

    • puis celle portant le nom de votre migration, dans mon cas : ex_042_001_EF_CF_conventions.NounoursSet.mdf

    • puis Tables

    • Faites un clic droit sur la table dbo.Nounours puis choisissez Afficher les données

    • Vous devriez maintenant pouvoir voir les données suivantes dans le tableau :

    ID Nom DateDeNaissance NbPoils
    1 Chewbacca 27/05/1977 00:00:00 1234567
    2 Yoda 21/05/1980 00:00:00 3
    3 Ewok 25/05/1983 00:00:00 3456789

Note: les identifiants peuvent varier en fonction du nombre d'exécution de l'exemple depuis la création de la base de données.