Marc CHEVALDONNE
a773557095
continuous-integration/drone/push Build is failing
Details
|
2 years ago | |
---|---|---|
.. | ||
Cylon.cs | 5 years ago | |
DBEntities.cs | 5 years ago | |
Nounours.cs | 5 years ago | |
Ordinateur.cs | 5 years ago | |
Program.cs | 5 years ago | |
ReadMe.md | 5 years ago | |
ex_042_006_Keys_FluentAPI.csproj | 2 years ago |
ReadMe.md
ex_042_006_Keys_FluentAPI
07/01/2020 ⋅ Marc Chevaldonné
Cet exemple traite des clés primaires associées aux entités.
Prérequis : je n'explique pas à travers cet exemple les principes de base d'Entity Framework Core et en particulier les chaînes de connexion et le lien entre entité et table. Pour plus de renseignements sur :
- les chaînes de connexion : ex_041_001_ConnectionStrings
- les liens entre entités et tables : ex_042_001_EF_CF_conventions, ex_042_002_EF_CF_data_annotations et ex_042_003_EF_CF_Fluent_API
Cet exemple montre le cas particulier de la gestion des clés primaires lors de l'utilisation la Fluent API.
Vous pourrez trouver une version plus ou moins équivalente avec les conventions d'écriture ici : ex_042_004_Keys_conventions.
Vous pourrez trouver une version plus ou moins équivalente avec la data annotations ici : ex_042_005_Keys_data_annotations.
Les clés primaires
Une clé permet de rendre unique chaque instance d'une entité. La plupart des entités n'ont qu'une seule clé qui est alors transformée en clé primaire pour les bases de données relationnelles.
Note: une entité peut avoir d'autres clés, on parle d'alternate keys. Elles seront présentées dans les exemples sur les relations entre entités.
Si on utilise la Fluent API, une propriété pour être transformée en clé doit respecter les contraintes suivantes
(toutes les modifications se font dans la méthode OnModelCreating
de votre classe dérivant de DbContext
) :
- aucune contrainte sur le nommage de la propriété ; j'ai par exemple choisi
UniqueId
pourNounours
, etFrakId
pourCylon
. - on définit qu'une propriété est une clé primaire avec la méthode d'extension
HasKey
sur la classeEntity
.
//définition de la clé primaire de Nounours
modelBuilder.Entity<Nounours>().HasKey(n => n.UniqueId);
//définition de la clé primaire de Cylon
modelBuilder.Entity<Cylon>().HasKey(c => c.FrakId);
- elle peut être générée par la base et dans ce cas, on ajoute à la
Property
la méthode d'extensionValueGeneratedOnAdd()
.
//définition du mode de génération de la clé : génération à l'insertion
modelBuilder.Entity<Nounours>().Property(n => n.UniqueId).ValueGeneratedOnAdd();
- elle peut ne pas être générée par la base et être gérée par l'utilisateur, dans ce cas on utilise la méthode d'extension
ValueGeneratedNever()
. Dans ce dernier cas, c'est à l'utilisateur de gérer ses propres clés et leur unicité dans la base.
//définition du mode de génération de la clé : génération gérée par l'utilisateur (jamais par la base)
modelBuilder.Entity<Cylon>().Property(c => c.FrakId).ValueGeneratedNever();
- elle peut être de différents types
int
,string
,Guid
,byte[]
... attention toutefois si vous choisissez de laisser la table générer les valeurs car certains fournisseurs ne savent pas générer tous les types.
Les clés primaires composites
En Fluent API (et seulement en Fluent API), on peut définir des clés composites, c'est-à-dire se basant sur plusieurs propriétés.
Pour cela, on utilise également HasKey
et on l'associe à un type anonyme, comme par exemple pour la classe Ordinateur
dans cet exemple, dont la clé est un composite des propriétés CodeId
et Modele
.
Ainsi, dans la méthode OnModelCreating
de votre classe dérivant de DbContext
, on ajoute :
//définition d'une clé primaire composite pour Ordinateur
modelBuilder.Entity<Ordinateur>().HasKey(o => new { o.CodeId, o.Modele });
Les clés composites ne peuvent pas être générées par la base.
Les classes POCO Nounours
, Cylon
et Ordinateur
Lorsqu'on utilise la Fluent API, ces classes n'ont aucune annotation. La classe Ordinateur
n'a pas de propriété "Id".
La classe DBEntites : DbContext
La classe dérivant de DbContext
ressemble dès lors dans notre exemple à :
using Microsoft.EntityFrameworkCore;
namespace ex_042_006_Keys_FluentAPI
{
class DBEntities : DbContext
{
public DbSet<Nounours> NounoursSet { get; set; }
public DbSet<Cylon> CylonsSet { get; set; }
public DbSet<Ordinateur> Ordinateurs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ex_042_006_Keys_FluentAPI.Nounours.mdf;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//définition de la clé primaire de Nounours
modelBuilder.Entity<Nounours>().HasKey(n => n.UniqueId);
//définition du mode de génération de la clé : génération à l'insertion
modelBuilder.Entity<Nounours>().Property(n => n.UniqueId).ValueGeneratedOnAdd();
//définition de la clé primaire de Cylon
modelBuilder.Entity<Cylon>().HasKey(c => c.FrakId);
//définition du mode de génération de la clé : génération gérée par l'utilisateur (jamais par la base)
modelBuilder.Entity<Cylon>().Property(c => c.FrakId).ValueGeneratedNever();
//définition d'une clé primaire composite pour Ordinateur
modelBuilder.Entity<Ordinateur>().HasKey(o => new { o.CodeId, o.Modele });
//une clé composite ne peut pas être générée par la base
base.OnModelCreating(modelBuilder);
}
}
}
La classe Program
Cette classe est le point d'entrée du programme :
- Elle crée des instances de
Nounours
, deCylon
et d'Ordinateur
et les ajoute en base après avoir nettoyé les tables au préalables.
Notez que l'utilisateur n'a pas besoin de donner une valeur àNounours.UniqueId
puisque la base s'en charge, alors qu'il doit donner une valeur àCylon.FrakId
car la base de ne génère pas les clés.
Si vous ne donnez pas une valeur àCylon.FrakId
, alors la valeur par défaut est donnée (0
). Il n'y aura pas de problème si cet identifiant n'a pas été donné, mais dès le deuxièmeCylon
, vous aurez une exception.
Note : la valeur par défaut pourint
est0
; pourGuid
,Guid.Empty
; pourstring
,null
...
Notez que l'utilisateur doit garantir pour ses instances d'Ordinateur
l'unicité des couplesCodeId
/Modele
, puisqu'il s'agit d'une clé composite.
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 };
Cylon c1 = new Cylon { FrakId = 2, Name = "John Cavil", Generation = 1 };
Cylon c2 = new Cylon { FrakId = 4, Name = "Leoben Conoy", Generation = 2 };
Cylon c3 = new Cylon { FrakId = 6, Name = "D'Anna Biers", Generation = 3 };
Cylon c4 = new Cylon { FrakId = 8, Name = "Simon", Generation = 4 };
Cylon c5 = new Cylon { FrakId = 10, Name = "Aaron Doral", Generation = 5 };
Cylon c6 = new Cylon { FrakId = 12, Name = "Caprica 6", Generation = 6 };
Cylon c7 = new Cylon { FrakId = 14, Name = "Daniel", Generation = 7 };
Cylon c8 = new Cylon { FrakId = 16, Name = "Boomer", Generation = 8 };
Cylon c9 = new Cylon { FrakId = 17, Name = "Athena", Generation = 8 };
Ordinateur o1 = new Ordinateur { Année = 2019, Modele = "MacBook Pro", CodeId = "IUT_1" };
Ordinateur o2 = new Ordinateur { Année = 2017, Modele = "MacBook Pro", CodeId = "IUT_2" };
Ordinateur o3 = new Ordinateur { Année = 2016, Modele = "MacBook Pro", CodeId = "IUT_4" };
Ordinateur o4 = new Ordinateur { Année = 2019, Modele = "Dell Latitude", CodeId = "IUT_1" };
Ordinateur o5 = new Ordinateur { Année = 2012, Modele = "Dell Latitude", CodeId = "IUT_2" };
Ordinateur o6 = new Ordinateur { Année = 2013, Modele = "Dell Latitude", CodeId = "IUT_3" };
- Elle affiche les
Nounours
, lesCylon
et lesOrdinateur
. Notez la génération des identifiants pour la classeNounours
uniquement : si vous exécutez plusieurs fois l'exemple, les clés desNounours
changent mais pas celles desCylon
.
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_006_Keys_FluentAPI
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_006
- 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_006_Keys_FluentAPI.
-
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_006_Keys_FluentAPI.Nounours.mdf
- puis Tables
- Faites un clic droit sur la table dbo.Nounours puis choisissez Afficher les données
-
Le résultat de l'exécution peut être :
database after cleaning and adding 3 Nounours and 9 Cylons and saving changes :
Nounours 1: Chewbacca (27/05/1977, 1234567 poils)
Nounours 2: Ewok (25/05/1983, 3456789 poils)
Nounours 3: Yoda (21/05/1980, 3 poils)
Cylon 2: John Cavil, Number 1
Cylon 4: Leoben Conoy, Number 2
Cylon 6: D'Anna Biers, Number 3
Cylon 8: Simon, Number 4
Cylon 10: Aaron Doral, Number 5
Cylon 12: Caprica 6, Number 6
Cylon 14: Daniel, Number 7
Cylon 16: Boomer, Number 8
Cylon 17: Athena, Number 8
Computer IUT_1 (Dell Latitude, 2019)
Computer IUT_1 (MacBook Pro, 2019)
Computer IUT_2 (Dell Latitude, 2012)
Computer IUT_2 (MacBook Pro, 2017)
Computer IUT_3 (Dell Latitude, 2013)
Computer IUT_4 (MacBook Pro, 2016)
Note: les identifiants des Nounours
peuvent varier en fonction du nombre d'exécution de l'exemple depuis la création de la base de données, mais pas ceux des Cylon
puisqu'ils sont gérés par l'utilisateur.