parent
ffc8759b77
commit
57f501c0f1
@ -0,0 +1,171 @@
|
||||
# ex_042_004_ValueGeneration_conventions
|
||||
*04/01/2020 ⋅ Marc Chevaldonné*
|
||||
|
||||
---
|
||||
|
||||
Cet exemple traite de la génération des valeurs de propriétés par la base de données, lors de l'ajout ou de l'insertion.
|
||||
|
||||
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 génération de valeurs lors de l'utilisation des **conventions d'écriture**.
|
||||
Vous pourrez trouver une version plus ou moins équivalente avec les *data annotations* ici : **ex_042_005_ValueGeneration_DataAnnotations**.
|
||||
Vous pourrez trouver une version plus ou moins équivalente avec la *Fluent API* ici : **ex_042_006_ValueGeneration_FluentAPI**.
|
||||
|
||||
---
|
||||
|
||||
## La génération de valeurs
|
||||
**Entity Framework Core** propose trois solutions de génération de valeurs :
|
||||
* **None** : c'est à l'utilisateur de donner une valeur avant l'insertion, sinon, la valeur par défaut du type est utilisée.
|
||||
Par défaut, c'est le mode utilisé pour toutes les propriétés, sauf les clés primaires. C'est donc uniquement dans ce cas qu'on devra chercher à l'utiliser si on veut gérer soi-même les valeurs des clés.
|
||||
* **Generated on add** : on demande à la base de générer une valeur lors de l'insertion en base d'un nouvel élément.
|
||||
Pour savoir si l'élément est nouveau, **EF Core** regarde si l'entité était déjà en base ou non. Si la valeur de la propriété de la clé primaire à générer est la valeur par défaut (par exemple, ```null``` pour ```string```, ```0```pour ```int```, ```Guid.Empty``` pour ```Guid```...), une nouvelle valeur est générée, sinon, rien n'est changé.
|
||||
Ce mode est souvent utilisé pour les clés primaires ou les dates.
|
||||
* **Generated on add or update** : on demande à la base de générer une valeur lors de l'insertion ou de la mise à jour de l'élément en base.
|
||||
Ce mode est souvent utilisé pour les dates représentant des mises à jour.
|
||||
|
||||
## La classe ```Nounours```
|
||||
La classe ```Nounours``` utilise les conventions d'écriture.
|
||||
* Par défaut, les propriétés utilisées comme clés primaires sont en mode **Generated on add**.
|
||||
Une nouvelle valeur est donc générée lors de l'insertion d'une nouvelle entité en base. Les valeurs des autres propriétés ne sont pas générées lors de l'insertion ou de la mise à jour.
|
||||
```csharp
|
||||
public class Nounours
|
||||
{
|
||||
public int ID
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string Nom
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public DateTime DateDeNaissance
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public int NbPoils
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**En résumé** :
|
||||
Si on utilise des conventions d'écriture :
|
||||
* seule la propriété utilisée comme clé primaire est générée lors de l'insertion en table : elle est reconnue si elle a un nom reconnu pour être une clé ("ID" par exemple) ; la génération a lieu si le type peut être utilisé (```int```, ```Guid```, ...).
|
||||
* toutes les autres propriétés sont en mode **None**, c'est-à-dire que les valeurs ne sont jamais générées pas la base.
|
||||
|
||||
### La classe ```Program```
|
||||
Cette classe est le point d'entrée du programme :
|
||||
* Elle crée des instances de ```Nounours```
|
||||
```csharp
|
||||
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
|
||||
```csharp
|
||||
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._
|
||||
```csharp
|
||||
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 ```Nounours```et sauvegarde les changements pour que ceux-ci soit effectivement ajoutés à la base.
|
||||
```csharp
|
||||
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```
|
||||
|
||||
* 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**.
|
||||
|
||||
* Comment vérifier le contenu des bases de données SQL Server et SQLite ?
|
||||
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*.
|
||||
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_01.png" width="500"/>
|
||||
|
||||
* 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*
|
||||
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_02.png" width="460"/>
|
||||
|
||||
* 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.*
|
@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.0"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in new issue