diff --git a/Exemples.sln b/Exemples.sln
index fd19b98..7e8742e 100644
--- a/Exemples.sln
+++ b/Exemples.sln
@@ -568,6 +568,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_042_004_Keys_conventions
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ex_042_005_Keys_data_annotations", "p08_BDD_EntityFramework\ex_042_005_Keys_data_annotations\ex_042_005_Keys_data_annotations.csproj", "{27725449-27B2-47ED-A2B3-738851E55C64}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ex_042_006_Keys_FluentAPI", "p08_BDD_EntityFramework\ex_042_006_Keys_FluentAPI\ex_042_006_Keys_FluentAPI.csproj", "{64EA0021-231A-421F-A616-3973C0106E99}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ex_042_007_ValueGeneration", "p08_BDD_EntityFramework\ex_042_007_ValueGeneration\ex_042_007_ValueGeneration.csproj", "{DA7ADAF3-34FF-4B97-8306-EF490A7A713A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -4724,6 +4728,46 @@ Global
{27725449-27B2-47ED-A2B3-738851E55C64}.Release|x64.Build.0 = Release|Any CPU
{27725449-27B2-47ED-A2B3-738851E55C64}.Release|x86.ActiveCfg = Release|Any CPU
{27725449-27B2-47ED-A2B3-738851E55C64}.Release|x86.Build.0 = Release|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Debug|ARM.Build.0 = Debug|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Debug|x64.Build.0 = Debug|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Debug|x86.Build.0 = Debug|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Release|Any CPU.Build.0 = Release|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Release|ARM.ActiveCfg = Release|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Release|ARM.Build.0 = Release|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Release|ARM64.Build.0 = Release|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Release|x64.ActiveCfg = Release|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Release|x64.Build.0 = Release|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Release|x86.ActiveCfg = Release|Any CPU
+ {64EA0021-231A-421F-A616-3973C0106E99}.Release|x86.Build.0 = Release|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Debug|ARM.Build.0 = Debug|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Debug|x64.Build.0 = Debug|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Debug|x86.Build.0 = Debug|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Release|ARM.ActiveCfg = Release|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Release|ARM.Build.0 = Release|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Release|ARM64.Build.0 = Release|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Release|x64.ActiveCfg = Release|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Release|x64.Build.0 = Release|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Release|x86.ActiveCfg = Release|Any CPU
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -4993,6 +5037,8 @@ Global
{BAB08578-898E-48C5-8470-6AC72D49B0D8} = {5B333C02-67B7-4A4C-AA58-2710C183292B}
{DBEE3EA3-9B59-4688-B7D7-6A4ABA6E1991} = {5B333C02-67B7-4A4C-AA58-2710C183292B}
{27725449-27B2-47ED-A2B3-738851E55C64} = {5B333C02-67B7-4A4C-AA58-2710C183292B}
+ {64EA0021-231A-421F-A616-3973C0106E99} = {5B333C02-67B7-4A4C-AA58-2710C183292B}
+ {DA7ADAF3-34FF-4B97-8306-EF490A7A713A} = {5B333C02-67B7-4A4C-AA58-2710C183292B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8D31C3AE-36FF-4667-A2A7-0E670245A59E}
diff --git a/p08_BDD_EntityFramework/ReadMe.md b/p08_BDD_EntityFramework/ReadMe.md
index 8a38e6f..7a4e8e5 100644
--- a/p08_BDD_EntityFramework/ReadMe.md
+++ b/p08_BDD_EntityFramework/ReadMe.md
@@ -27,6 +27,8 @@ Ce chapitre s'attardera sur le lien entre le mod
* **ex_042_003 : Fluent API** : explique comment utiliser la *Fluent API* pour personnaliser la transformation d'une entité en table.
* **ex_042_004 : Keys with conventions** : explique comment créer les clés primaires d'une entité lorsqu'on utilise les conventions d'écriture.
* **ex_042_005 : Keys with data annotations** : explique comment créer les clés primaires d'une entité lorsqu'on utilise les *data annotations*.
+ * **ex_042_006 : Keys with Fluent API** : explique comment créer les clés primaires d'une entité lorsqu'on utilise la *Fluent API*.
+ * **ex_042_007 : Value Generation** : explique comment faire générer des valeurs automatiquement lors de l'insertion ou de la mise à jour
3. *Schemas and migrations* :
Le but de ce chapitre sera de vous montrer comment garder votre modèle et votre base de données synchronisés.
@@ -137,7 +139,10 @@ dotnet ef database update
Si vous n'avez pas installé correctement EntityFrameworkCore, il vous faudra peut-être utiliser également :
-```dotnet tool install --global dotnet-ef```
+* ```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.
+
##### Utilisez votre base de données via Entity Framework Core
* Editez *Program.cs* et ajoutez le code suivant :
diff --git a/p08_BDD_EntityFramework/ex_041_001_ConnectionStrings/ReadMe.md b/p08_BDD_EntityFramework/ex_041_001_ConnectionStrings/ReadMe.md
index 2d8be25..c960f6b 100644
--- a/p08_BDD_EntityFramework/ex_041_001_ConnectionStrings/ReadMe.md
+++ b/p08_BDD_EntityFramework/ex_041_001_ConnectionStrings/ReadMe.md
@@ -51,7 +51,10 @@ cd .\p08_BDD_EntityFramework\ex_041_001_ConnectionStrings
*Note*:
si vous n'avez pas installé correctement EntityFrameworkCore, il vous faudra peut-être utiliser également :
-```dotnet tool install --global dotnet-ef```
+* ```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.
+
### Migrations
*Note :* normalement, la commande pour effectuer une migration est :
@@ -72,6 +75,12 @@ dotnet ef database update --context SQLiteContext
### Génération et exécution
Vous pouvez maintenant générer et exécuter l'exemple.
+Le résultat de l'exécution peut donner :
+```
+Creates and inserts new Nounours
+Creates and inserts new Nounours
+```
+
## Comment vérifier le contenu des bases de données SQL Server et SQLite ?
### SqlServer
Vous pouvez vérifier le contenu de votre base en utilisant l'*Explorateur d'objets SQL Server*.
diff --git a/p08_BDD_EntityFramework/ex_041_004_TestingInMemory/ReadMe.md b/p08_BDD_EntityFramework/ex_041_004_TestingInMemory/ReadMe.md
index 3625d45..1346fa6 100644
--- a/p08_BDD_EntityFramework/ex_041_004_TestingInMemory/ReadMe.md
+++ b/p08_BDD_EntityFramework/ex_041_004_TestingInMemory/ReadMe.md
@@ -121,7 +121,10 @@ cd .\p08_BDD_EntityFramework\ex_041_004_ConsoleTests_w_SqlServer
*Note*:
si vous n'avez pas installé correctement EntityFrameworkCore, il vous faudra peut-être utiliser également :
-```dotnet tool install --global dotnet-ef```
+* ```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 : comme la classe dérivant de ```DbContext``` n'est pas dans l'application Console, nous devons préciser dans quel projet elle se trouve en ajoutant ```--project ../ex_041_004_TestingInMemory```.
```
@@ -134,7 +137,11 @@ dotnet ef database update --project ../ex_041_004_TestingInMemory
* Génération et exécution
Vous pouvez maintenant générer et exécuter l'exemple **ex_041_004_ConsoleTests_w_SqlServer**.
- * Comment vérifier le contenu des bases de données SQL Server et SQLite ?
+ * Le résultat de l'exécution doit ressembler à :
+ ```
+Creates and inserts new Nounours
+```
+ * 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*.
diff --git a/p08_BDD_EntityFramework/ex_042_001_EF_CF_conventions/Nounours.cs b/p08_BDD_EntityFramework/ex_042_001_EF_CF_conventions/Nounours.cs
index 9554707..0f5be79 100644
--- a/p08_BDD_EntityFramework/ex_042_001_EF_CF_conventions/Nounours.cs
+++ b/p08_BDD_EntityFramework/ex_042_001_EF_CF_conventions/Nounours.cs
@@ -27,51 +27,6 @@ namespace ex_042_001_EF_CF_conventions
set;
}
- ///
- /// returns a hash code in order to use this class in hash table
- ///
- /// hash code
- public override int GetHashCode()
- {
- return Nom.GetHashCode();
- }
-
- ///
- /// checks if the "right" object is equal to this Nounours or not
- ///
- /// the other object to be compared with this Nounours
- /// true if equals, false if not
- public override bool Equals(object right)
- {
- //check null
- if (object.ReferenceEquals(right, null))
- {
- return false;
- }
-
- if (object.ReferenceEquals(this, right))
- {
- return true;
- }
-
- if (this.GetType() != right.GetType())
- {
- return false;
- }
-
- return this.Equals(right as Nounours);
- }
-
- ///
- /// checks if this Nounours is equal to the other Nounours
- ///
- /// the other Nounours to be compared with
- /// true if equals
- public bool Equals(Nounours other)
- {
- return (this.Nom.Equals(other.Nom) && this.DateDeNaissance == other.DateDeNaissance);
- }
-
public override string ToString()
{
return $"{ID}: {Nom} ({DateDeNaissance:dd/MM/yyyy}, {NbPoils} poils)";
diff --git a/p08_BDD_EntityFramework/ex_042_001_EF_CF_conventions/ReadMe.md b/p08_BDD_EntityFramework/ex_042_001_EF_CF_conventions/ReadMe.md
index 420d40e..a1c006b 100644
--- a/p08_BDD_EntityFramework/ex_042_001_EF_CF_conventions/ReadMe.md
+++ b/p08_BDD_EntityFramework/ex_042_001_EF_CF_conventions/ReadMe.md
@@ -173,7 +173,10 @@ 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```
+* ```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 :
```
@@ -186,7 +189,16 @@ 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 ?
+ * 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*.
diff --git a/p08_BDD_EntityFramework/ex_042_002_EF_CF_data_annotations/Nounours.cs b/p08_BDD_EntityFramework/ex_042_002_EF_CF_data_annotations/Nounours.cs
index 2605649..75f809b 100644
--- a/p08_BDD_EntityFramework/ex_042_002_EF_CF_data_annotations/Nounours.cs
+++ b/p08_BDD_EntityFramework/ex_042_002_EF_CF_data_annotations/Nounours.cs
@@ -37,51 +37,6 @@ namespace ex_042_002_EF_CF_data_annotations
set;
}
- ///
- /// returns a hash code in order to use this class in hash table
- ///
- /// hash code
- public override int GetHashCode()
- {
- return Nom.GetHashCode();
- }
-
- ///
- /// checks if the "right" object is equal to this Nounours or not
- ///
- /// the other object to be compared with this Nounours
- /// true if equals, false if not
- public override bool Equals(object right)
- {
- //check null
- if (object.ReferenceEquals(right, null))
- {
- return false;
- }
-
- if (object.ReferenceEquals(this, right))
- {
- return true;
- }
-
- if (this.GetType() != right.GetType())
- {
- return false;
- }
-
- return this.Equals(right as Nounours);
- }
-
- ///
- /// checks if this Nounours is equal to the other Nounours
- ///
- /// the other Nounours to be compared with
- /// true if equals
- public bool Equals(Nounours other)
- {
- return (this.Nom.Equals(other.Nom) && this.DateDeNaissance == other.DateDeNaissance);
- }
-
public override string ToString()
{
return $"{UniqueId}: {Nom} ({DateDeNaissance:dd/MM/yyyy}, {NbPoils} poils)";
diff --git a/p08_BDD_EntityFramework/ex_042_002_EF_CF_data_annotations/ReadMe.md b/p08_BDD_EntityFramework/ex_042_002_EF_CF_data_annotations/ReadMe.md
index 6374883..892ba58 100644
--- a/p08_BDD_EntityFramework/ex_042_002_EF_CF_data_annotations/ReadMe.md
+++ b/p08_BDD_EntityFramework/ex_042_002_EF_CF_data_annotations/ReadMe.md
@@ -91,37 +91,6 @@ public class Nounours
set;
}
- public override int GetHashCode()
- {
- return Nom.GetHashCode();
- }
-
- public override bool Equals(object right)
- {
- //check null
- if (object.ReferenceEquals(right, null))
- {
- return false;
- }
-
- if (object.ReferenceEquals(this, right))
- {
- return true;
- }
-
- if (this.GetType() != right.GetType())
- {
- return false;
- }
-
- return this.Equals(right as Nounours);
- }
-
- public bool Equals(Nounours other)
- {
- return (this.Nom.Equals(other.Nom) && this.DateDeNaissance == other.DateDeNaissance);
- }
-
public override string ToString()
{
return $"{UniqueId}: {Nom} ({DateDeNaissance:dd/MM/yyyy}, {NbPoils} poils)";
@@ -288,9 +257,10 @@ cd .\p08_BDD_EntityFramework\ex_042_002_EF_CF_data_annotations
*Note*:
si vous n'avez pas installé correctement EntityFrameworkCore, il vous faudra peut-être utiliser également :
-```
-dotnet tool install --global dotnet-ef
-```
+* ```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 :
```
@@ -303,7 +273,16 @@ dotnet ef database update
* Génération et exécution
Vous pouvez maintenant générer et exécuter l'exemple **ex_042_002_EF_CF_data_annotations**.
- * Comment vérifier le contenu des bases de données SQL Server et SQLite ?
+ * Le résultat de l'exécution peut ressembler à :
+ ```
+Base après ajout des 3 nounours et sauvegarde des changements :
+ fbc3f7c5-a333-4d07-f7f2-08d7907e5437: Chewbacca (27/05/1977, 1234567 poils)
+ 63b18e10-a683-4144-f7f3-08d7907e5437: Yoda (21/05/1980, 3 poils)
+ c4eab29b-315b-416e-f7f4-08d7907e5437: Ewok (25/05/1983, 3456789 poils)
+```
+_Note : les identifiants seront bien sûr différents_
+
+ * 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*.
@@ -319,12 +298,10 @@ Vous pouvez vérifier le contenu de votre base en utilisant l'*Explorateur d'obj
* Vous devriez maintenant pouvoir voir les données suivantes dans le tableau :
- |UniqueId |Nom|Naissance
- |---|---|---
- |fbc3f7c5-a333-4d07-f7f2-08d7907e5437|Chewbacca|27/05/1977
- |63b18e10-a683-4144-f7f3-08d7907e5437|Yoda|21/05/1980
- |c4eab29b-315b-416e-f7f4-08d7907e5437|Ewok|25/05/1983
+ |UniqueId |Nom|Naissance|NbPoils|DateDInsertion|DernièreModification
+ |---|---|---|---|---|---
+ |49102173-b82a-4b4d-1d02-08d793b46eb3|Chewbacca|27/05/1977|1234567|07/01/2020 20:59:05|07/01/2020 20:59:08
+ |ae2ab1fa-ac8d-4df9-1d03-08d793b46eb3|Yoda|21/05/1980|3|07/01/2020 20:59:05|07/01/2020 20:59:05
+ |ccee4eaf-4b50-48ec-1d04-08d793b46eb3||07/01/2020|0|07/01/2020 20:59:05|07/01/2020 20:59:05
-*Notes: les identifiants seront bien sûr différents.*
-*Notez l'absence de la colonne "NbPoils"*
-*Notez le nom de la colonne "Naissance" et le formatage de la date*
\ No newline at end of file
+*Note : les identifiants seront bien sûr différents.*
diff --git a/p08_BDD_EntityFramework/ex_042_003_EF_CF_Fluent_API/Nounours.cs b/p08_BDD_EntityFramework/ex_042_003_EF_CF_Fluent_API/Nounours.cs
index 8cbf24b..30ae52b 100644
--- a/p08_BDD_EntityFramework/ex_042_003_EF_CF_Fluent_API/Nounours.cs
+++ b/p08_BDD_EntityFramework/ex_042_003_EF_CF_Fluent_API/Nounours.cs
@@ -27,51 +27,6 @@ namespace ex_042_003_EF_CF_Fluent_API
set;
}
- ///
- /// returns a hash code in order to use this class in hash table
- ///
- /// hash code
- public override int GetHashCode()
- {
- return Nom.GetHashCode();
- }
-
- ///
- /// checks if the "right" object is equal to this Nounours or not
- ///
- /// the other object to be compared with this Nounours
- /// true if equals, false if not
- public override bool Equals(object right)
- {
- //check null
- if (object.ReferenceEquals(right, null))
- {
- return false;
- }
-
- if (object.ReferenceEquals(this, right))
- {
- return true;
- }
-
- if (this.GetType() != right.GetType())
- {
- return false;
- }
-
- return this.Equals(right as Nounours);
- }
-
- ///
- /// checks if this Nounours is equal to the other Nounours
- ///
- /// the other Nounours to be compared with
- /// true if equals
- public bool Equals(Nounours other)
- {
- return (this.Nom.Equals(other.Nom) && this.DateDeNaissance == other.DateDeNaissance);
- }
-
public override string ToString()
{
return $"{UniqueId}: {Nom} ({DateDeNaissance:dd/MM/yyyy}, {NbPoils} poils)";
diff --git a/p08_BDD_EntityFramework/ex_042_003_EF_CF_Fluent_API/ReadMe.md b/p08_BDD_EntityFramework/ex_042_003_EF_CF_Fluent_API/ReadMe.md
index 3d6ce42..987060d 100644
--- a/p08_BDD_EntityFramework/ex_042_003_EF_CF_Fluent_API/ReadMe.md
+++ b/p08_BDD_EntityFramework/ex_042_003_EF_CF_Fluent_API/ReadMe.md
@@ -256,9 +256,10 @@ cd .\p08_BDD_EntityFramework\ex_042_003_EF_CF_Fluent_API
*Note*:
si vous n'avez pas installé correctement EntityFrameworkCore, il vous faudra peut-être utiliser également :
-```
-dotnet tool install --global dotnet-ef
-```
+* ```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 :
```
@@ -270,8 +271,17 @@ dotnet ef database update
```
* Génération et exécution
Vous pouvez maintenant générer et exécuter l'exemple **ex_042_003_EF_CF_Fluent_API**.
+
+ * Le résultat de l'exécution pourra ressembler à :
+ ```
+Base après ajout des 3 nounours et sauvegarde des changements :
+ 30817fff-8736-457d-db18-08d7908d7986: Chewbacca (27/05/1977, 1234567 poils)
+ aa4469c4-a6c8-4077-db19-08d7908d7986: Yoda (21/05/1980, 3 poils)
+ 69cb5892-6750-4629-db1a-08d7908d7986: Ewok (25/05/1983, 3456789 poils)
+```
+*Notes: les identifiants seront bien sûr différents.*
- * Comment vérifier le contenu des bases de données SQL Server et SQLite ?
+ * 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*.
diff --git a/p08_BDD_EntityFramework/ex_042_004_Keys_conventions/Nounours.cs b/p08_BDD_EntityFramework/ex_042_004_Keys_conventions/Nounours.cs
index 5acaab6..40ce89c 100644
--- a/p08_BDD_EntityFramework/ex_042_004_Keys_conventions/Nounours.cs
+++ b/p08_BDD_EntityFramework/ex_042_004_Keys_conventions/Nounours.cs
@@ -27,51 +27,6 @@ namespace ex_042_004_Keys_conventions
set;
}
- ///
- /// returns a hash code in order to use this class in hash table
- ///
- /// hash code
- public override int GetHashCode()
- {
- return Nom.GetHashCode();
- }
-
- ///
- /// checks if the "right" object is equal to this Nounours or not
- ///
- /// the other object to be compared with this Nounours
- /// true if equals, false if not
- public override bool Equals(object right)
- {
- //check null
- if (object.ReferenceEquals(right, null))
- {
- return false;
- }
-
- if (object.ReferenceEquals(this, right))
- {
- return true;
- }
-
- if (this.GetType() != right.GetType())
- {
- return false;
- }
-
- return this.Equals(right as Nounours);
- }
-
- ///
- /// checks if this Nounours is equal to the other Nounours
- ///
- /// the other Nounours to be compared with
- /// true if equals
- public bool Equals(Nounours other)
- {
- return (this.Nom.Equals(other.Nom) && this.DateDeNaissance == other.DateDeNaissance);
- }
-
public override string ToString()
{
return $"Nounours {ID}: {Nom} ({DateDeNaissance:dd/MM/yyyy}, {NbPoils} poils)";
diff --git a/p08_BDD_EntityFramework/ex_042_004_Keys_conventions/ReadMe.md b/p08_BDD_EntityFramework/ex_042_004_Keys_conventions/ReadMe.md
index 8531e00..13613e4 100644
--- a/p08_BDD_EntityFramework/ex_042_004_Keys_conventions/ReadMe.md
+++ b/p08_BDD_EntityFramework/ex_042_004_Keys_conventions/ReadMe.md
@@ -67,7 +67,10 @@ cd .\p08_BDD_EntityFramework\ex_042_004_Keys_conventions
*Note*:
si vous n'avez pas installé correctement EntityFrameworkCore, il vous faudra peut-être utiliser également :
-```dotnet tool install --global dotnet-ef```
+* ```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 :
```
@@ -80,7 +83,7 @@ dotnet ef database update
* Génération et exécution
Vous pouvez maintenant générer et exécuter l'exemple **ex_042_004_Keys_conventions**.
- * Comment vérifier le contenu des bases de données SQL Server et SQLite ?
+ * 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*.
diff --git a/p08_BDD_EntityFramework/ex_042_004_ValueGeneration_conventions/Nounours.cs b/p08_BDD_EntityFramework/ex_042_004_ValueGeneration_conventions/Nounours.cs
deleted file mode 100644
index 44d0b03..0000000
--- a/p08_BDD_EntityFramework/ex_042_004_ValueGeneration_conventions/Nounours.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using System;
-
-namespace ex_042_004_ValueGeneration_conventions
-{
- public class Nounours
- {
- public int ID
- {
- get; set;
- }
-
- public string Nom
- {
- get;
- set;
- }
-
- public DateTime DateDeNaissance
- {
- get;
- set;
- }
-
- public int NbPoils
- {
- get;
- set;
- }
-
- ///
- /// returns a hash code in order to use this class in hash table
- ///
- /// hash code
- public override int GetHashCode()
- {
- return Nom.GetHashCode();
- }
-
- ///
- /// checks if the "right" object is equal to this Nounours or not
- ///
- /// the other object to be compared with this Nounours
- /// true if equals, false if not
- public override bool Equals(object right)
- {
- //check null
- if (object.ReferenceEquals(right, null))
- {
- return false;
- }
-
- if (object.ReferenceEquals(this, right))
- {
- return true;
- }
-
- if (this.GetType() != right.GetType())
- {
- return false;
- }
-
- return this.Equals(right as Nounours);
- }
-
- ///
- /// checks if this Nounours is equal to the other Nounours
- ///
- /// the other Nounours to be compared with
- /// true if equals
- public bool Equals(Nounours other)
- {
- return (this.Nom.Equals(other.Nom) && this.DateDeNaissance == other.DateDeNaissance);
- }
-
- public override string ToString()
- {
- return $"{ID}: {Nom} ({DateDeNaissance:dd/MM/yyyy}, {NbPoils} poils)";
- }
-
- }
-}
diff --git a/p08_BDD_EntityFramework/ex_042_004_ValueGeneration_conventions/NounoursDBEntities.cs b/p08_BDD_EntityFramework/ex_042_004_ValueGeneration_conventions/NounoursDBEntities.cs
deleted file mode 100644
index 51225c8..0000000
--- a/p08_BDD_EntityFramework/ex_042_004_ValueGeneration_conventions/NounoursDBEntities.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Microsoft.EntityFrameworkCore;
-
-namespace ex_042_004_ValueGeneration_conventions
-{
- class NounoursDBEntities : DbContext
- {
- public virtual DbSet NounoursSet { get; set; }
-
-
- protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
- {
- optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ex_042_004_ValueGeneration_conventions.Nounours.mdf;Trusted_Connection=True;");
- }
- }
-}
diff --git a/p08_BDD_EntityFramework/ex_042_004_ValueGeneration_conventions/Program.cs b/p08_BDD_EntityFramework/ex_042_004_ValueGeneration_conventions/Program.cs
deleted file mode 100644
index 12c7d71..0000000
--- a/p08_BDD_EntityFramework/ex_042_004_ValueGeneration_conventions/Program.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using Microsoft.Data.SqlClient;
-using Microsoft.EntityFrameworkCore;
-using System;
-using System.Linq;
-using static System.Console;
-
-namespace ex_042_004_ValueGeneration_conventions
-{
- class Program
- {
- static void Main(string[] args)
- {
- OutputEncoding = System.Text.Encoding.UTF8;
-
- 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 ();
-
- try
- {
- using (NounoursDBEntities db = new NounoursDBEntities())
- {
- //nettoyage de la base de données
- if (db.NounoursSet.Count() > 0)
- {
- foreach (var n in db.NounoursSet)
- {
- db.NounoursSet.Remove(n);
- }
- db.SaveChanges();
- }
-
- //ajout des nounours dans la base de données
- db.NounoursSet.AddRange(new Nounours[] { chewie, yoda, ewok });
- db.SaveChanges();
-
- WriteLine("database after cleaning and adding 3 Nounours and saving changes :");
- foreach (var n in db.NounoursSet)
- {
- WriteLine($"\t{n}");
- }
-
- //essai d'ajout d'un Nounours existant
- try
- {
- WriteLine("\nTry to insert an existing entity");
- chewie.Nom = "Chewie";
- db.NounoursSet.Add(chewie);
- db.SaveChanges();
- }
- catch (DbUpdateException exc)
- {
- WriteLine(exc.Message);
- }
-
- WriteLine("\nDisplay the last Nounours with default values");
- Nounours e = db.NounoursSet.ToList().Last();
- string nameStr = e.Nom != null ? e.Nom : "null";
- WriteLine($"Name: {nameStr}; BirthDate: {e.DateDeNaissance}; Hair count: {e.NbPoils}");
- }
- }
- catch (SqlException)
- {
- WriteLine("Votre base de données n'existe pas. C'est peut-être la première fois que vous exécutez cet exemple.");
- WriteLine("Pour créer la base de données, suivez les instructions données dans le fichier ReadMe.md associé à cet exemple.");
- }
-
- ReadLine();
- }
- }
-}
diff --git a/p08_BDD_EntityFramework/ex_042_004_ValueGeneration_conventions/ReadMe.md b/p08_BDD_EntityFramework/ex_042_004_ValueGeneration_conventions/ReadMe.md
deleted file mode 100644
index 9d1918c..0000000
--- a/p08_BDD_EntityFramework/ex_042_004_ValueGeneration_conventions/ReadMe.md
+++ /dev/null
@@ -1,175 +0,0 @@
-# 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_data_annotations**.
-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```
-Notez que la dernière ne donne aucune valeur pour les propriétés pour tester les valeurs par défaut.
-```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 ();
-```
-* 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.
-Elle ajoute ensuite les ```Nounours```et sauvegarde les changements pour que ceux-ci soit effectivement ajoutés à la base.
-Notez la création automatique des ID.
-_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
-//nettoyage de la base de données
-if (db.NounoursSet.Count() > 0)
-{
- foreach (var n in db.NounoursSet)
- {
- db.NounoursSet.Remove(n);
- }
- db.SaveChanges();
-}
-
-//ajout des nounours dans la base de données
-db.NounoursSet.AddRange(new Nounours[] { chewie, yoda, ewok });
-db.SaveChanges();
-
-WriteLine("database after cleaning and adding 3 Nounours and saving changes :");
-foreach (var n in db.NounoursSet)
-{
- WriteLine($"\t{n}");
-}
-```
-* Elle tente d'ajouter une entité dont l'ID n'est pas l'identifiant par défaut (0) à la base. Ceci lance une ```DbUpdateException```.
-```csharp
-//essai d'ajout d'un Nounours existant
-try
-{
- WriteLine("\nTry to insert an existing entity");
- chewie.Nom = "Chewie";
- db.NounoursSet.Add(chewie);
- db.SaveChanges();
-}
-catch (DbUpdateException exc)
-{
- WriteLine(exc.Message);
-}
-```
-* Elle affiche les valeurs des propriétés du dernier Nounours pour montrer les valeurs par défaut : ```null``` pour le ```string```, ```0``` pour l'```int```, ```01/01/0001 00:00:00``` pour le ```DateTime```.
-```csharp
-WriteLine("\nDisplay the last Nounours with default values");
-Nounours e = db.NounoursSet.ToList().Last();
-string nameStr = e.Nom != null ? e.Nom : "null";
-WriteLine($"Name: {nameStr}; BirthDate: {e.DateDeNaissance}; Hair count: {e.NbPoils}");
-```
-
-## 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_004_ValueGeneration_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_004
-```
- * 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_004_ValueGeneration_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*.
-
-
-* 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_004_ValueGeneration_conventions.Nounours.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|NULL|01/01/0001 00:00:00|0
-
-*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.*
\ No newline at end of file
diff --git a/p08_BDD_EntityFramework/ex_042_005_Keys_data_annotations/Nounours.cs b/p08_BDD_EntityFramework/ex_042_005_Keys_data_annotations/Nounours.cs
index 6db9406..533f763 100644
--- a/p08_BDD_EntityFramework/ex_042_005_Keys_data_annotations/Nounours.cs
+++ b/p08_BDD_EntityFramework/ex_042_005_Keys_data_annotations/Nounours.cs
@@ -31,51 +31,6 @@ namespace ex_042_005_Keys_data_annotations
set;
}
- ///
- /// returns a hash code in order to use this class in hash table
- ///
- /// hash code
- public override int GetHashCode()
- {
- return Nom.GetHashCode();
- }
-
- ///
- /// checks if the "right" object is equal to this Nounours or not
- ///
- /// the other object to be compared with this Nounours
- /// true if equals, false if not
- public override bool Equals(object right)
- {
- //check null
- if (object.ReferenceEquals(right, null))
- {
- return false;
- }
-
- if (object.ReferenceEquals(this, right))
- {
- return true;
- }
-
- if (this.GetType() != right.GetType())
- {
- return false;
- }
-
- return this.Equals(right as Nounours);
- }
-
- ///
- /// checks if this Nounours is equal to the other Nounours
- ///
- /// the other Nounours to be compared with
- /// true if equals
- public bool Equals(Nounours other)
- {
- return (this.Nom.Equals(other.Nom) && this.DateDeNaissance == other.DateDeNaissance);
- }
-
public override string ToString()
{
return $"Nounours {UniqueId}: {Nom} ({DateDeNaissance:dd/MM/yyyy}, {NbPoils} poils)";
diff --git a/p08_BDD_EntityFramework/ex_042_005_Keys_data_annotations/ReadMe.md b/p08_BDD_EntityFramework/ex_042_005_Keys_data_annotations/ReadMe.md
index 1651f1a..b500021 100644
--- a/p08_BDD_EntityFramework/ex_042_005_Keys_data_annotations/ReadMe.md
+++ b/p08_BDD_EntityFramework/ex_042_005_Keys_data_annotations/ReadMe.md
@@ -82,7 +82,10 @@ cd .\p08_BDD_EntityFramework\ex_042_005_Keys_data_annotations
*Note*:
si vous n'avez pas installé correctement EntityFrameworkCore, il vous faudra peut-être utiliser également :
-```dotnet tool install --global dotnet-ef```
+* ```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 :
```
@@ -95,7 +98,7 @@ dotnet ef database update
* Génération et exécution
Vous pouvez maintenant générer et exécuter l'exemple **ex_042_005_Keys_data_annotations**.
- * Comment vérifier le contenu des bases de données SQL Server et SQLite ?
+ * 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*.
@@ -104,7 +107,7 @@ Vous pouvez vérifier le contenu de votre base en utilisant l'*Explorateur d'obj
* *SQL Server*,
* puis *(localdb)\MSSQLLocalDB ...*,
* puis *Bases de données*
- * puis celle portant le nom de votre migration, dans mon cas : *ex_042_004_Keys_conventions.Nounours.mdf*
+ * puis celle portant le nom de votre migration, dans mon cas : *ex_042_005_Keys_data_annotations.Nounours.mdf*
* puis *Tables*
* Faites un clic droit sur la table *dbo.Nounours* puis choisissez *Afficher les données*
diff --git a/p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/Nounours.cs b/p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/Nounours.cs
deleted file mode 100644
index d68360f..0000000
--- a/p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/Nounours.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-using System;
-using System.ComponentModel.DataAnnotations;
-using System.ComponentModel.DataAnnotations.Schema;
-
-namespace ex_042_005_ValueGeneration_data_annotations
-{
- [Table("TableNounours")]
- public class Nounours
- {
- [Key]
- [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public Guid UniqueId
- {
- get; set;
- }
-
- [Required]
- [MaxLength(256)]
- public string Nom
- {
- get;
- set;
- }
-
- [Column("Naissance", TypeName = "date")]
- public DateTime DateDeNaissance
- {
- get;
- set;
- }
-
- [NotMapped]
- public int NbPoils
- {
- get;
- set;
- }
-
- [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public DateTime InsertionDate
- {
- get; set;
- }
-
- [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public DateTime LastModified
- {
- get; set;
- }
-
- ///
- /// returns a hash code in order to use this class in hash table
- ///
- /// hash code
- public override int GetHashCode()
- {
- return Nom.GetHashCode();
- }
-
- ///
- /// checks if the "right" object is equal to this Nounours or not
- ///
- /// the other object to be compared with this Nounours
- /// true if equals, false if not
- public override bool Equals(object right)
- {
- //check null
- if (object.ReferenceEquals(right, null))
- {
- return false;
- }
-
- if (object.ReferenceEquals(this, right))
- {
- return true;
- }
-
- if (this.GetType() != right.GetType())
- {
- return false;
- }
-
- return this.Equals(right as Nounours);
- }
-
- ///
- /// checks if this Nounours is equal to the other Nounours
- ///
- /// the other Nounours to be compared with
- /// true if equals
- public bool Equals(Nounours other)
- {
- return (this.Nom.Equals(other.Nom) && this.DateDeNaissance == other.DateDeNaissance);
- }
-
- public override string ToString()
- {
- return $"{UniqueId}: {Nom} ({DateDeNaissance:dd/MM/yyyy}, {NbPoils} poils, Inserted on:{InsertionDate}, Last modified on: {LastModified})";
- }
-
- }
-}
diff --git a/p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/NounoursDBEntities.cs b/p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/NounoursDBEntities.cs
deleted file mode 100644
index 4fea1de..0000000
--- a/p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/NounoursDBEntities.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using Microsoft.EntityFrameworkCore;
-
-namespace ex_042_005_ValueGeneration_data_annotations
-{
- class NounoursDBEntities : DbContext
- {
- public virtual DbSet NounoursSet { get; set; }
-
-
- protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
- {
- optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ex_042_005_ValueGeneration_data_annotations.Nounours.mdf;Trusted_Connection=True;");
- //optionsBuilder.UseSqlite($"Data Source=ex_042_005_ValueGeneration_data_annotations.Nounours.db");
- }
-
- internal static string DefaultValues = @"ALTER TABLE [dbo].[TableNounours] ADD CONSTRAINT DF_TableNounours DEFAULT GETDATE() FOR InsertionDate
-ALTER TABLE [dbo].[TableNounours] ADD CONSTRAINT DF_TableNounours2 DEFAULT GETDATE() FOR LastModified";
-
- internal static string InsertionDateTrigger = @"CREATE TRIGGER [dbo].[InsertionDateTrigger]
- ON [dbo].[TableNounours]
- AFTER INSERT
-AS
-BEGIN
- SET NOCOUNT ON;
-
- IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;
-
- DECLARE @Id uniqueidentifier
-
- SELECT @Id = INSERTED.UniqueId
- FROM INSERTED
-
- UPDATE dbo.TableNounours
- SET InsertionDate = GETDATE(), LastModified = GETDATE()
- WHERE UniqueId = @Id
-END";
-
- internal static string LastModifiedTrigger = @"CREATE TRIGGER [dbo].[LastModifiedTrigger]
- ON [dbo].[TableNounours]
- AFTER UPDATE
-AS
-BEGIN
- SET NOCOUNT ON;
-
- IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;
-
- DECLARE @Id uniqueidentifier
-
- SELECT @Id = INSERTED.UniqueId
- FROM INSERTED
-
- UPDATE dbo.TableNounours
- SET LastModified = GETDATE()
- WHERE UniqueId = @Id
-END";
- }
-}
diff --git a/p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/Program.cs b/p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/Program.cs
deleted file mode 100644
index 723c570..0000000
--- a/p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/Program.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using Microsoft.Data.SqlClient;
-using Microsoft.EntityFrameworkCore;
-using System;
-using System.Linq;
-using static System.Console;
-
-namespace ex_042_005_ValueGeneration_data_annotations
-{
- class Program
- {
- static void Main(string[] args)
- {
- OutputEncoding = System.Text.Encoding.UTF8;
-
- 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 ();
-
- try
- {
- using (NounoursDBEntities db = new NounoursDBEntities())
- {
- //nettoyage de la base de données
- if (db.NounoursSet.Count() > 0)
- {
- foreach (var n in db.NounoursSet)
- {
- db.NounoursSet.Remove(n);
- }
- db.SaveChanges();
- }
-
- //ajout des nounours dans la base de données
- db.NounoursSet.AddRange(new Nounours[] { chewie, yoda, ewok });
- db.SaveChanges();
-
- WriteLine("database after cleaning and adding 3 Nounours and saving changes :");
- foreach (var n in db.NounoursSet)
- {
- WriteLine($"\t{n}");
- }
-
- //essai d'ajout d'un Nounours existant
- try
- {
- WriteLine("\nTry to insert an existing entity");
- chewie.Nom = "Chewie";
- db.NounoursSet.Add(chewie);
- db.SaveChanges();
- }
- catch (DbUpdateException exc)
- {
- WriteLine(exc.Message);
- }
-
- //modification d'un Nounours existant
- WriteLine("\nModification of the name of Chewbacca to Chewie");
- chewie.Nom = "Chewie";
- db.NounoursSet.Add(chewie);
- db.SaveChanges();
- foreach (var n in db.NounoursSet)
- {
- WriteLine($"\t{n}");
- }
-
- WriteLine("\nDisplay the last Nounours with default values");
- Nounours e = db.NounoursSet.ToList().Last();
- string nameStr = e.Nom != null ? e.Nom : "null";
- WriteLine($"Name: {nameStr}; BirthDate: {e.DateDeNaissance}; Hair count: {e.NbPoils}");
- }
- }
- catch (SqlException)
- {
- WriteLine("Votre base de données n'existe pas. C'est peut-être la première fois que vous exécutez cet exemple.");
- WriteLine("Pour créer la base de données, suivez les instructions données dans le fichier ReadMe.md associé à cet exemple.");
- }
-
- ReadLine();
- }
- }
-}
diff --git a/p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/ReadMe.md b/p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/ReadMe.md
deleted file mode 100644
index d62d872..0000000
--- a/p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/ReadMe.md
+++ /dev/null
@@ -1,247 +0,0 @@
-# ex_042_005_ValueGeneration_data_annotations
-*05/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 **data annotations**.
-Vous pourrez trouver une version plus ou moins équivalente avec les *conventions d'écriture* ici : **ex_042_004_ValueGeneration_conventions**.
-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 *data annotations*.
-```csharp
-[Table("TableNounours")]
-public class Nounours
-{
- [Key]
- [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public Guid UniqueId
- {
- get; set;
- }
-
- [Required]
- [MaxLength(256)]
- public string Nom
- {
- get;
- set;
- }
-
- [Column("Naissance", TypeName = "date")]
- public DateTime DateDeNaissance
- {
- get;
- set;
- }
-
- [NotMapped]
- public int NbPoils
- {
- get;
- set;
- }
-
- [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public DateTime InsertionDate
- {
- get; set;
- }
-
- [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
- public DateTime LastModified
- {
- get; set;
- }
-
- ///...
-}
-```
-
-* 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 si on ne précise rien.
-* Dans la classe ```Nounours```, on peut donc voir que les propriétés : ```Nom``` et ```DateDeNaissance``` n'ont pas de valeurs pas générées lors de l'insertion ou de la mise à jour (mode par défaut). (```NbPoils``` n'est pas *mappée*).
-* ```csharp
-[Required]
-[MaxLength(256)]
-public string Nom
-{
- get;
- set;
-}
-
-[Column("Naissance", TypeName = "date")]
-public DateTime DateDeNaissance
-{
- get;
- set;
-}
-
-[NotMapped]
-public int NbPoils
-{
- get;
- set;
-}
-```
-* La propriété ```UniqueId``` est remise à jour lors de l'insertion en base (grâce à ```DatabaseGenerated(DatabaseGeneratedOption.Identity)```).
-```csharp
-[Key]
-[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
-public Guid UniqueId
-{
- get; set;
-}
-```
-* La propriété ```InsertionDate``` est remise à jour lors de l'insertion en base (grâce à ```DatabaseGenerated(DatabaseGeneratedOption.Identity)```).
-```csharp
-[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
-public DateTime InsertionDate
-{
- get; set;
-}
-```
-* La propriété ```LastModified``` est remise à jour lors de l'insertion ou de la mise à jour d'une propriété en base (grâce à ```DatabaseGenerated(DatabaseGeneratedOption.Computed)```).
-```csharp
-[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
-public DateTime LastModified
-{
- 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```
-Notez que la dernière ne donne aucune valeur pour les propriétés pour tester les valeurs par défaut.
-```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 ();
-```
-* 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.
-Elle ajoute ensuite les ```Nounours```et sauvegarde les changements pour que ceux-ci soit effectivement ajoutés à la base.
-Notez la création automatique des ID.
-_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
-//nettoyage de la base de données
-if (db.NounoursSet.Count() > 0)
-{
- foreach (var n in db.NounoursSet)
- {
- db.NounoursSet.Remove(n);
- }
- db.SaveChanges();
-}
-
-//ajout des nounours dans la base de données
-db.NounoursSet.AddRange(new Nounours[] { chewie, yoda, ewok });
-db.SaveChanges();
-
-WriteLine("database after cleaning and adding 3 Nounours and saving changes :");
-foreach (var n in db.NounoursSet)
-{
- WriteLine($"\t{n}");
-}
-```
-* Elle tente d'ajouter une entité dont l'ID n'est pas l'identifiant par défaut (0) à la base. Ceci lance une ```DbUpdateException```.
-```csharp
-//essai d'ajout d'un Nounours existant
-try
-{
- WriteLine("\nTry to insert an existing entity");
- chewie.Nom = "Chewie";
- db.NounoursSet.Add(chewie);
- db.SaveChanges();
-}
-catch (DbUpdateException exc)
-{
- WriteLine(exc.Message);
-}
-```
-* Elle affiche les valeurs des propriétés du dernier Nounours pour montrer les valeurs par défaut : ```null``` pour le ```string```, ```0``` pour l'```int```, ```01/01/0001 00:00:00``` pour le ```DateTime```.
-```csharp
-WriteLine("\nDisplay the last Nounours with default values");
-Nounours e = db.NounoursSet.ToList().Last();
-string nameStr = e.Nom != null ? e.Nom : "null";
-WriteLine($"Name: {nameStr}; BirthDate: {e.DateDeNaissance}; Hair count: {e.NbPoils}");
-```
-
-## 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_004_ValueGeneration_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_004
-```
- * 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_004_ValueGeneration_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*.
-
-
-* 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_004_ValueGeneration_conventions.Nounours.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|NULL|01/01/0001 00:00:00|0
-
-*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.*
\ No newline at end of file
diff --git a/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/Cylon.cs b/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/Cylon.cs
new file mode 100644
index 0000000..045bfeb
--- /dev/null
+++ b/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/Cylon.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Text;
+
+namespace ex_042_006_Keys_FluentAPI
+{
+ public class Cylon
+ {
+ public int FrakId
+ {
+ get; set;
+ }
+
+ public string Name
+ {
+ get; set;
+ }
+
+ public int Generation
+ {
+ get; set;
+ }
+
+ public override string ToString()
+ {
+ return $"Cylon {FrakId}: {Name}, Number {Generation}";
+ }
+ }
+}
diff --git a/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/DBEntities.cs b/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/DBEntities.cs
new file mode 100644
index 0000000..5e7fd39
--- /dev/null
+++ b/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/DBEntities.cs
@@ -0,0 +1,36 @@
+using Microsoft.EntityFrameworkCore;
+
+namespace ex_042_006_Keys_FluentAPI
+{
+ class DBEntities : DbContext
+ {
+ public virtual DbSet NounoursSet { get; set; }
+ public virtual DbSet CylonsSet { get; set; }
+ public virtual DbSet 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().HasKey(n => n.UniqueId);
+ //définition du mode de génération de la clé : génération à l'insertion
+ modelBuilder.Entity().Property(n => n.UniqueId).ValueGeneratedOnAdd();
+
+ //définition de la clé primaire de Cylon
+ modelBuilder.Entity().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().Property(c => c.FrakId).ValueGeneratedNever();
+
+ //définition d'une clé primaire composite pour Ordinateur
+ modelBuilder.Entity().HasKey(o => new { o.CodeId, o.Modele });
+ //une clé composite ne peut pas être générée par la base
+
+ base.OnModelCreating(modelBuilder);
+ }
+ }
+}
diff --git a/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/Nounours.cs b/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/Nounours.cs
new file mode 100644
index 0000000..e608a6c
--- /dev/null
+++ b/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/Nounours.cs
@@ -0,0 +1,38 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace ex_042_006_Keys_FluentAPI
+{
+ public class Nounours
+ {
+ public int UniqueId
+ {
+ get; set;
+ }
+
+ public string Nom
+ {
+ get;
+ set;
+ }
+
+ public DateTime DateDeNaissance
+ {
+ get;
+ set;
+ }
+
+ public int NbPoils
+ {
+ get;
+ set;
+ }
+
+ public override string ToString()
+ {
+ return $"Nounours {UniqueId}: {Nom} ({DateDeNaissance:dd/MM/yyyy}, {NbPoils} poils)";
+ }
+
+ }
+}
diff --git a/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/Ordinateur.cs b/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/Ordinateur.cs
new file mode 100644
index 0000000..5055bed
--- /dev/null
+++ b/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/Ordinateur.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ex_042_006_Keys_FluentAPI
+{
+ class Ordinateur
+ {
+ public string Modele
+ {
+ get; set;
+ }
+
+ public string CodeId
+ {
+ get; set;
+ }
+
+ public int Année
+ {
+ get; set;
+ }
+
+ public override string ToString()
+ {
+ return $"Computer {CodeId} ({Modele}, {Année})";
+ }
+ }
+}
diff --git a/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/Program.cs b/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/Program.cs
new file mode 100644
index 0000000..0b5cd0d
--- /dev/null
+++ b/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/Program.cs
@@ -0,0 +1,100 @@
+using Microsoft.Data.SqlClient;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Linq;
+using static System.Console;
+
+namespace ex_042_006_Keys_FluentAPI
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ OutputEncoding = System.Text.Encoding.UTF8;
+
+ 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" };
+
+ try
+ {
+ using (DBEntities db = new DBEntities())
+ {
+ //nettoyage de la base de données
+ if (db.NounoursSet.Count() > 0)
+ {
+ foreach (var n in db.NounoursSet)
+ {
+ db.NounoursSet.Remove(n);
+ }
+ db.SaveChanges();
+ }
+
+ if (db.CylonsSet.Count() > 0)
+ {
+ foreach (var c in db.CylonsSet)
+ {
+ db.CylonsSet.Remove(c);
+ }
+ db.SaveChanges();
+ }
+
+ if (db.Ordinateurs.Count() > 0)
+ {
+ foreach (var o in db.Ordinateurs)
+ {
+ db.Ordinateurs.Remove(o);
+ }
+ db.SaveChanges();
+ }
+
+ //ajout des nounours dans la base de données
+ db.NounoursSet.AddRange(new Nounours[] { chewie, yoda, ewok });
+ db.CylonsSet.AddRange(new Cylon[] { c1, c2, c3, c4, c5, c6, c7, c8, c9 });
+ db.Ordinateurs.AddRange(new Ordinateur[] { o1, o2, o3, o4, o5, o6 });
+ db.SaveChanges();
+ }
+ using (DBEntities db = new DBEntities())
+ {
+ WriteLine("database after cleaning and adding 3 Nounours and 9 Cylons and saving changes :");
+ foreach (var n in db.NounoursSet)
+ {
+ WriteLine($"\t{n}");
+ }
+ foreach (var c in db.CylonsSet)
+ {
+ WriteLine($"\t{c}");
+ }
+ foreach (var o in db.Ordinateurs)
+ {
+ WriteLine($"\t{o}");
+ }
+ }
+ }
+ catch (SqlException)
+ {
+ WriteLine("Votre base de données n'existe pas. C'est peut-être la première fois que vous exécutez cet exemple.");
+ WriteLine("Pour créer la base de données, suivez les instructions données dans le fichier ReadMe.md associé à cet exemple.");
+ }
+
+ ReadLine();
+ }
+ }
+}
diff --git a/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/ReadMe.md b/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/ReadMe.md
new file mode 100644
index 0000000..9b71a80
--- /dev/null
+++ b/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/ReadMe.md
@@ -0,0 +1,195 @@
+# 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``` pour ```Nounours```, et ```FrakId``` pour ```Cylon```.
+* on définit qu'une propriété est une clé primaire avec la méthode d'extension ```HasKey``` sur la classe ```Entity```.
+```csharp
+//définition de la clé primaire de Nounours
+modelBuilder.Entity().HasKey(n => n.UniqueId);
+```
+```csharp
+//définition de la clé primaire de Cylon
+modelBuilder.Entity().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'extension ```ValueGeneratedOnAdd()```.
+```csharp
+//définition du mode de génération de la clé : génération à l'insertion
+modelBuilder.Entity().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.
+```csharp
+//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().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 :
+```csharp
+//définition d'une clé primaire composite pour Ordinateur
+modelBuilder.Entity().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 à :
+```csharp
+using Microsoft.EntityFrameworkCore;
+
+namespace ex_042_006_Keys_FluentAPI
+{
+ class DBEntities : DbContext
+ {
+ public virtual DbSet NounoursSet { get; set; }
+ public virtual DbSet CylonsSet { get; set; }
+ public virtual DbSet 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().HasKey(n => n.UniqueId);
+ //définition du mode de génération de la clé : génération à l'insertion
+ modelBuilder.Entity().Property(n => n.UniqueId).ValueGeneratedOnAdd();
+
+ //définition de la clé primaire de Cylon
+ modelBuilder.Entity().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().Property(c => c.FrakId).ValueGeneratedNever();
+
+ //définition d'une clé primaire composite pour Ordinateur
+ modelBuilder.Entity().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```, de ```Cylon``` 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ème ```Cylon```, vous aurez une exception.
+_Note : la valeur par défaut pour ```int``` est ```0``` ; pour ```Guid```, ```Guid.Empty``` ; pour ```string```, ```null```..._
+Notez que l'utilisateur doit garantir pour ses instances d'```Ordinateur``` l'unicité des couples ```CodeId```/```Modele```, puisqu'il s'agit d'une clé composite.
+```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 };
+
+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```, les ```Cylon``` et les ```Ordinateur```.
+*Notez la génération des identifiants pour la classe ```Nounours``` uniquement : si vous exécutez plusieurs fois l'exemple, les clés des ```Nounours``` changent mais pas celles des ```Cylon```.*
+
+## 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.*
\ No newline at end of file
diff --git a/p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/ex_042_005_ValueGeneration_data_annotations.csproj b/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/ex_042_006_Keys_FluentAPI.csproj
similarity index 95%
rename from p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/ex_042_005_ValueGeneration_data_annotations.csproj
rename to p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/ex_042_006_Keys_FluentAPI.csproj
index 8fe0f0a..7b1d557 100644
--- a/p08_BDD_EntityFramework/ex_042_005_ValueGeneration_data_annotations/ex_042_005_ValueGeneration_data_annotations.csproj
+++ b/p08_BDD_EntityFramework/ex_042_006_Keys_FluentAPI/ex_042_006_Keys_FluentAPI.csproj
@@ -7,6 +7,6 @@
-
+
diff --git a/p08_BDD_EntityFramework/ex_042_006_ValueGeneration_FluentAPI/Nounours.cs b/p08_BDD_EntityFramework/ex_042_006_ValueGeneration_FluentAPI/Nounours.cs
deleted file mode 100644
index 655c1e8..0000000
--- a/p08_BDD_EntityFramework/ex_042_006_ValueGeneration_FluentAPI/Nounours.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-using System;
-using System.ComponentModel.DataAnnotations;
-using System.ComponentModel.DataAnnotations.Schema;
-
-namespace ex_042_006_ValueGeneration_FluentAPI
-{
- public class Nounours
- {
- public Guid UniqueId
- {
- get; set;
- }
-
- public string Nom
- {
- get;
- set;
- }
-
- public DateTime DateDeNaissance
- {
- get;
- set;
- }
-
- public int NbPoils
- {
- get;
- set;
- }
-
- public DateTime InsertionDate
- {
- get; set;
- }
-
- public DateTime LastModified
- {
- get; set;
- }
-
- ///
- /// returns a hash code in order to use this class in hash table
- ///
- /// hash code
- public override int GetHashCode()
- {
- return Nom.GetHashCode();
- }
-
- ///
- /// checks if the "right" object is equal to this Nounours or not
- ///
- /// the other object to be compared with this Nounours
- /// true if equals, false if not
- public override bool Equals(object right)
- {
- //check null
- if (object.ReferenceEquals(right, null))
- {
- return false;
- }
-
- if (object.ReferenceEquals(this, right))
- {
- return true;
- }
-
- if (this.GetType() != right.GetType())
- {
- return false;
- }
-
- return this.Equals(right as Nounours);
- }
-
- ///
- /// checks if this Nounours is equal to the other Nounours
- ///
- /// the other Nounours to be compared with
- /// true if equals
- public bool Equals(Nounours other)
- {
- return (this.Nom.Equals(other.Nom) && this.DateDeNaissance == other.DateDeNaissance);
- }
-
- public override string ToString()
- {
- return $"{UniqueId}: {Nom} ({DateDeNaissance:dd/MM/yyyy}, {NbPoils} poils, Inserted on: {InsertionDate}, Last modified on: {LastModified})";
- }
-
- }
-}
diff --git a/p08_BDD_EntityFramework/ex_042_006_ValueGeneration_FluentAPI/NounoursDBEntities.cs b/p08_BDD_EntityFramework/ex_042_006_ValueGeneration_FluentAPI/NounoursDBEntities.cs
deleted file mode 100644
index f2355db..0000000
--- a/p08_BDD_EntityFramework/ex_042_006_ValueGeneration_FluentAPI/NounoursDBEntities.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using Microsoft.EntityFrameworkCore;
-using System;
-using System.Linq;
-
-namespace ex_042_006_ValueGeneration_FluentAPI
-{
- class NounoursDBEntities : DbContext
- {
- public virtual DbSet NounoursSet { get; set; }
-
-
- protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
- {
- optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ex_042_006_ValueGeneration_FluentAPI.Nounours.mdf;Trusted_Connection=True;");
- //optionsBuilder.UseSqlite($"Data Source=ex_042_005_ValueGeneration_data_annotations.Nounours.db");
- }
-
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- //ici on précise comment s'appellera la table associée à la classe POCO Nounours
- //équivalent du [Table("TableNounours")] avec les annotations de données
- modelBuilder.Entity().ToTable("TableNounours");
-
- //ici on précise que la propriété UniqueId de Nounours est la clef primaire
- //équivalent de [Key] devant la propriété UniqueId dans Nounours
- modelBuilder.Entity().HasKey(n => n.UniqueId);
-
- //ici on explique que c'est lors de l'insertion en base que la clef primaire sera générée
- //équivalent de [DatabaseGenerated(DatabaseGeneratedOption.Identity)] devant la propriété UniqueId de Nounours
- modelBuilder.Entity().Property(n => n.UniqueId).ValueGeneratedOnAdd();
- //HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
-
- //ici on précise que la propriété Nom est obligatoire et que sa taille maximale est de 256 caractères
- //Notez l'utilisation des méthodes chaînées ! Trop beau ! Tellement pratique, intuitif et évident...
- //équivalent de [Required] et [MaxLength(256)] devant la propriété Nom de Nounours
- modelBuilder.Entity().Property(n => n.Nom).IsRequired()
- .HasMaxLength(256)
- .HasDefaultValue("John Doe");
-
- //ici on donne un nom à la colonne associée à la propriété DateDeNaissance
- //équivalent de [Column("Naissance")] devant la propriété DateDeNaissance de Nounours
- modelBuilder.Entity().Property(n => n.DateDeNaissance).HasColumnName("Naissance").HasColumnType("date");
-
- //ici on précise que la propriété NbPoils ne sera pas insérée en base
- //équivalent de [NotMapped] devant la propriété NbPoils de Nounours
- //modelBuilder.Entity().Ignore(n => n.NbPoils);
-
- modelBuilder.Entity().Property(n => n.InsertionDate)/*.ValueGeneratedOnAdd()*/.HasDefaultValue(DateTime.UtcNow);
- modelBuilder.Entity().Property(n => n.LastModified)/*.ValueGeneratedOnAddOrUpdate()*/.HasDefaultValue(DateTime.UtcNow);
-
- //if (this.Database.IsSqlServer())
- //{
- // modelBuilder.Entity().Property(n => n.InsertionDate).HasDefaultValueSql("getdate()");
- // modelBuilder.Entity().Property(n => n.LastModified).HasDefaultValueSql("getdate()");
-
- //}
-
- base.OnModelCreating(modelBuilder);
- }
-
- public override int SaveChanges()
- {
- ChangeTracker.DetectChanges();
-
- foreach (var item in ChangeTracker.Entries().Where(e => e.State == EntityState.Added))
- {
- item.Property(n => n.InsertionDate).CurrentValue = DateTime.UtcNow;
- item.Property(n => n.LastModified).CurrentValue = DateTime.UtcNow;
- }
-
- foreach (var item in ChangeTracker.Entries().Where(e => e.State == EntityState.Modified))
- {
- item.Property(n => n.LastModified).CurrentValue = DateTime.UtcNow;
- }
- return base.SaveChanges();
- }
- }
-}
diff --git a/p08_BDD_EntityFramework/ex_042_006_ValueGeneration_FluentAPI/ex_042_006_ValueGeneration_FluentAPI.csproj b/p08_BDD_EntityFramework/ex_042_006_ValueGeneration_FluentAPI/ex_042_006_ValueGeneration_FluentAPI.csproj
deleted file mode 100644
index 7b54839..0000000
--- a/p08_BDD_EntityFramework/ex_042_006_ValueGeneration_FluentAPI/ex_042_006_ValueGeneration_FluentAPI.csproj
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- Exe
- netcoreapp3.0
-
-
-
-
-
-
-
diff --git a/p08_BDD_EntityFramework/ex_042_007_ValueGeneration/Nounours.cs b/p08_BDD_EntityFramework/ex_042_007_ValueGeneration/Nounours.cs
new file mode 100644
index 0000000..487ac73
--- /dev/null
+++ b/p08_BDD_EntityFramework/ex_042_007_ValueGeneration/Nounours.cs
@@ -0,0 +1,54 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace ex_042_007_ValueGeneration
+{
+ [Table("TableNounours")]
+ public class Nounours
+ {
+ [Key]
+ [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
+ public Guid UniqueId
+ {
+ get; set;
+ }
+
+ [Required]
+ [MaxLength(256)]
+ public string Nom
+ {
+ get;
+ set;
+ }
+
+ [Column("Naissance", TypeName = "date")]
+ public DateTime DateDeNaissance
+ {
+ get;
+ set;
+ }
+
+ public int NbPoils
+ {
+ get;
+ set;
+ }
+
+ public DateTime DateDInsertion
+ {
+ get; set;
+ }
+
+ public DateTime DernièreModification
+ {
+ get; set;
+ }
+
+ public override string ToString()
+ {
+ return $"{UniqueId}: {Nom} ({DateDeNaissance:dd/MM/yyyy}, {NbPoils} poils, Inserted on: {DateDInsertion}, Last modified on: {DernièreModification})";
+ }
+
+ }
+}
diff --git a/p08_BDD_EntityFramework/ex_042_007_ValueGeneration/NounoursDBEntities.cs b/p08_BDD_EntityFramework/ex_042_007_ValueGeneration/NounoursDBEntities.cs
new file mode 100644
index 0000000..6990054
--- /dev/null
+++ b/p08_BDD_EntityFramework/ex_042_007_ValueGeneration/NounoursDBEntities.cs
@@ -0,0 +1,44 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Linq;
+
+namespace ex_042_007_ValueGeneration
+{
+ class NounoursDBEntities : DbContext
+ {
+ public virtual DbSet NounoursSet { get; set; }
+
+
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ex_042_007_ValueGeneration.Nounours.mdf;Trusted_Connection=True;");
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.Entity().Property(n => n.Nom).HasDefaultValue("");
+ modelBuilder.Entity().Property(n => n.DateDeNaissance).HasDefaultValue(DateTime.UtcNow);
+ modelBuilder.Entity().Property(n => n.DateDInsertion).HasDefaultValue(DateTime.UtcNow);
+ modelBuilder.Entity().Property(n => n.DernièreModification).HasDefaultValue(DateTime.UtcNow);
+
+ base.OnModelCreating(modelBuilder);
+ }
+
+ public override int SaveChanges()
+ {
+ ChangeTracker.DetectChanges();
+
+ foreach (var item in ChangeTracker.Entries().Where(e => e.State == EntityState.Added))
+ {
+ item.Property(n => n.DateDInsertion).CurrentValue = DateTime.UtcNow;
+ item.Property(n => n.DernièreModification).CurrentValue = DateTime.UtcNow;
+ }
+
+ foreach (var item in ChangeTracker.Entries().Where(e => e.State == EntityState.Modified))
+ {
+ item.Property(n => n.DernièreModification).CurrentValue = DateTime.UtcNow;
+ }
+ return base.SaveChanges();
+ }
+ }
+}
diff --git a/p08_BDD_EntityFramework/ex_042_006_ValueGeneration_FluentAPI/Program.cs b/p08_BDD_EntityFramework/ex_042_007_ValueGeneration/Program.cs
similarity index 80%
rename from p08_BDD_EntityFramework/ex_042_006_ValueGeneration_FluentAPI/Program.cs
rename to p08_BDD_EntityFramework/ex_042_007_ValueGeneration/Program.cs
index c75f7d9..f2a1700 100644
--- a/p08_BDD_EntityFramework/ex_042_006_ValueGeneration_FluentAPI/Program.cs
+++ b/p08_BDD_EntityFramework/ex_042_007_ValueGeneration/Program.cs
@@ -4,7 +4,7 @@ using System;
using System.Linq;
using static System.Console;
-namespace ex_042_006_ValueGeneration_FluentAPI
+namespace ex_042_007_ValueGeneration
{
class Program
{
@@ -39,19 +39,6 @@ namespace ex_042_006_ValueGeneration_FluentAPI
{
WriteLine($"\t{n}");
}
-
- //essai d'ajout d'un Nounours existant
- try
- {
- WriteLine("\nTry to insert an existing entity");
- chewie.Nom = "Chewie";
- db.NounoursSet.Add(chewie);
- db.SaveChanges();
- }
- catch (DbUpdateException exc)
- {
- WriteLine(exc.Message);
- }
}
WriteLine("Waits 3 seconds...");
@@ -64,8 +51,11 @@ namespace ex_042_006_ValueGeneration_FluentAPI
WriteLine("\nModification of the name of Chewbacca to Chewie");
chewie = db.NounoursSet.First();
chewie.Nom = "Chewie";
- //db.NounoursSet.Add(chewie);
db.SaveChanges();
+ }
+
+ using (NounoursDBEntities db = new NounoursDBEntities())
+ {
foreach (var n in db.NounoursSet)
{
WriteLine($"\t{n}");
@@ -74,7 +64,7 @@ namespace ex_042_006_ValueGeneration_FluentAPI
WriteLine("\nDisplay the last Nounours with default values");
Nounours e = db.NounoursSet.ToList().Last();
string nameStr = e.Nom != null ? e.Nom : "null";
- WriteLine($"Name: {nameStr}; BirthDate: {e.DateDeNaissance}; Hair count: {e.NbPoils}; Insertion date: {e.InsertionDate}; LastModified: {e.LastModified}") ;
+ WriteLine($"Name: {nameStr}; BirthDate: {e.DateDeNaissance}; Hair count: {e.NbPoils}; Insertion date: {e.DateDInsertion}; LastModified: {e.DernièreModification}") ;
}
}
catch (SqlException)
diff --git a/p08_BDD_EntityFramework/ex_042_007_ValueGeneration/ReadMe.md b/p08_BDD_EntityFramework/ex_042_007_ValueGeneration/ReadMe.md
new file mode 100644
index 0000000..a48310d
--- /dev/null
+++ b/p08_BDD_EntityFramework/ex_042_007_ValueGeneration/ReadMe.md
@@ -0,0 +1,284 @@
+# ex_042_007_ValueGeneration
+*07/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*
+* il est conseillé d'avoir également lu les exemples sur les clés primaires : *ex_042_004_Keys_conventions*, *ex_042_005_Keys_data_annotations* et *ex_042_006_Keys_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.
+
+Néanmoins, je trouve que l'utilisation sur des propriétés autres que les clés primaires ou avec des types différents de ```int``` ou ```Guid``` n'est pas simple et varie beaucoup en fonction des fournisseurs.
+De plus, je pense que la génération de valeurs n'est généralement utilisée que pour des clés primaires, des dates (date de création, date de dernière modification) ou des *timestamps* (mais dans ce cas, d'autres mécanismes sont prévus).
+C'est la raison pour laquelle je pense qu'il est plus simple de se contenter de la réécriture de la méthode ```SaveChanges``` de votre contexte dérivant de ```DbContext```.
+Cet exemple propose cette méthode à travers l'ajout d'une date d'insertion et d'une date de dernière modification.
+
+## La classe ```Nounours```
+La classe ```Nounours``` utilise dans cet exemple les *data annotations*.
+Notez l'ajout des propriétés ```DateDInsertion``` et ```DernièreModification```, sans annotations.
+```csharp
+[Table("TableNounours")]
+public class Nounours
+{
+ [Key]
+ [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
+ public Guid UniqueId
+ {
+ get; set;
+ }
+
+ [Required]
+ [MaxLength(256)]
+ public string Nom
+ {
+ get;
+ set;
+ }
+
+ [Column("Naissance", TypeName = "date")]
+ public DateTime DateDeNaissance
+ {
+ get;
+ set;
+ }
+
+ public int NbPoils
+ {
+ get;
+ set;
+ }
+
+ public DateTime DateDInsertion
+ {
+ get; set;
+ }
+
+ public DateTime DernièreModification
+ {
+ get; set;
+ }
+}
+```
+
+## La classe NounoursDBEntites
+
+### Gestion des valeurs par défaut pour les dates.
+Dans la méthode ```OnModelCreating``` de ```NounoursDBEntites```, on ajoute deux lignes permettant de donner une valeur par défaut aux deux dates au cas où l'utilisateur de les rentrerait pas :
+```csharp
+protected override void OnModelCreating(ModelBuilder modelBuilder)
+{
+ modelBuilder.Entity().Property(n => n.Nom).HasDefaultValue("");
+ modelBuilder.Entity().Property(n => n.DateDeNaissance).HasDefaultValue(DateTime.UtcNow);
+ modelBuilder.Entity().Property(n => n.DateDInsertion).HasDefaultValue(DateTime.UtcNow);
+ modelBuilder.Entity().Property(n => n.DernièreModification).HasDefaultValue(DateTime.UtcNow);
+
+ base.OnModelCreating(modelBuilder);
+}
+```
+Remarque : ceci n'est pas obligatoire pour la génération de valeurs, c'est juste cadeau en passant. Le paragraphe suivant écrase ceci, sauf pour la ```DateDeNaissance```.
+
+### Génération des valeurs par la base
+Dans cette méthode, je décide de réécrire la méthode virtuelle ```SaveChanges``` de ```NounoursDBEntities```.
+```csharp
+public override int SaveChanges()
+{
+ ChangeTracker.DetectChanges();
+
+ foreach (var item in ChangeTracker.Entries().Where(e => e.State == EntityState.Added))
+ {
+ item.Property(n => n.DateDInsertion).CurrentValue = DateTime.UtcNow;
+ item.Property(n => n.DernièreModification).CurrentValue = DateTime.UtcNow;
+ }
+
+ foreach (var item in ChangeTracker.Entries().Where(e => e.State == EntityState.Modified))
+ {
+ item.Property(n => n.DernièreModification).CurrentValue = DateTime.UtcNow;
+ }
+ return base.SaveChanges();
+}
+```
+ * J'utilise dans cette méthode la propriété ```ChangeTracker``` de ```DbContext``` qui permet de garder la trace des modifications qui sont effectuées localement sur les entités avant la sauvegarde (update, delete, create...).
+ L'appel de la méthode ```DetectChanges()``` permet de garder la trace de toutes les modifications réalisées sur les instances.
+ * ```ChangeTracker``` me donne ainsi l'accès aux états des entités, de type ```EntityState```.
+ * La première requête LINQ me donne accès aux entités de type ```Nounours``` ayant été ajoutées sans être encore sauvegardées.
+```csharp
+ChangeTracker.Entries().Where(e => e.State == EntityState.Added)
+```
+Je récupère ainsi ces entités et modifie la valeur de leurs propriétés ```DateDInsertion``` et ```DernièreModification``` à maintenant (```DateTime.UtcNow```).
+```csharp
+item.Property(n => n.DateDInsertion).CurrentValue = DateTime.UtcNow;
+item.Property(n => n.DernièreModification).CurrentValue = DateTime.UtcNow;
+```
+* Je fais ensuite la même chose en récupérant les entités ayant été mises à jour, c'est-à -dire dont la propriété ```State``` vaut ```EntityState.Modified```, et je modifie leur propriété ```DernièreModification```.
+```csharp
+foreach (var item in ChangeTracker.Entries().Where(e => e.State == EntityState.Modified))
+{
+ item.Property(n => n.DernièreModification).CurrentValue = DateTime.UtcNow;
+}
+```
+* Enfin, j'appelle la méthode ```SaveChanges``` de la classe mère.
+
+En résumé, les valeurs ne sont pas générées sur la base, mais... on s'en fiche non ?
+
+## La classe ```Program```
+Cette classe est le point d'entrée du programme :
+* Elle crée des instances de ```Nounours```
+Notez que la dernière ne donne aucune valeur pour les propriétés pour tester les valeurs par défaut.
+```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 ();
+```
+* 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.
+Elle ajoute ensuite les ```Nounours```et sauvegarde les changements pour que ceux-ci soit effectivement ajoutés à la base.
+Notez la création automatique des ID.
+_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
+//nettoyage de la base de données
+if (db.NounoursSet.Count() > 0)
+{
+ foreach (var n in db.NounoursSet)
+ {
+ db.NounoursSet.Remove(n);
+ }
+ db.SaveChanges();
+}
+
+//ajout des nounours dans la base de données
+db.NounoursSet.AddRange(new Nounours[] { chewie, yoda, ewok });
+db.SaveChanges();
+
+WriteLine("database after cleaning and adding 3 Nounours and saving changes :");
+foreach (var n in db.NounoursSet)
+{
+ WriteLine($"\t{n}");
+}
+```
+* Elle attend ensuite 3 secondes (pour qu'on puisse voir la différence dans les dates entre la mise à jour et l'ajout), puis modifie le nom du premier ```Nounours```
+```csharp
+WriteLine("Waits 3 seconds...");
+System.Threading.Thread.Sleep(3000);
+
+using (NounoursDBEntities db = new NounoursDBEntities())
+{
+ //modification d'un Nounours existant
+ WriteLine("\nModification of the name of Chewbacca to Chewie");
+ chewie = db.NounoursSet.First();
+ chewie.Nom = "Chewie";
+ db.SaveChanges();
+}
+```
+* Enfin, elle affiche les ```Nounours```de la base une nouvelle fois, et les valeurs des propriétés du dernier Nounours pour montrer les valeurs par défaut : ```""``` pour le ```string```, ```0``` pour l'```int```, ```07/01/2020 00:00:00``` pour le ```DateTime```,
+Ã cause des lignes
+```csharp
+modelBuilder.Entity().Property(n => n.DateDeNaissance).HasDefaultValue(DateTime.UtcNow);
+modelBuilder.Entity().Property(n => n.Nom).HasDefaultValue("");
+```
+ajoutées à ```OnModelCreating```.
+
+```csharp
+using (NounoursDBEntities db = new NounoursDBEntities())
+{
+ foreach (var n in db.NounoursSet)
+ {
+ WriteLine($"\t{n}");
+ }
+
+ WriteLine("\nDisplay the last Nounours with default values");
+ Nounours e = db.NounoursSet.ToList().Last();
+ string nameStr = e.Nom != null ? e.Nom : "null";
+ WriteLine($"Name: {nameStr}; BirthDate: {e.DateDeNaissance}; Hair count: {e.NbPoils}; Insertion date: {e.DateDInsertion}; LastModified: {e.DernièreModification}") ;
+}
+```
+
+## 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_007_ValueGeneration
+```
+ *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_007
+```
+ * 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_007_ValueGeneration**.
+
+ * Le résultat de l'exécution ressemblera à :
+```
+database after cleaning and adding 3 Nounours and saving changes :
+ 49102173-b82a-4b4d-1d02-08d793b46eb3: Chewbacca (27/05/1977, 1234567 poils, Inserted on: 07/01/2020 20:59:05, Last modified on: 07/01/2020 20:59:05)
+ ae2ab1fa-ac8d-4df9-1d03-08d793b46eb3: Yoda (21/05/1980, 3 poils, Inserted on: 07/01/2020 20:59:05, Last modified on: 07/01/2020 20:59:05)
+ ccee4eaf-4b50-48ec-1d04-08d793b46eb3: (07/01/2020, 0 poils, Inserted on: 07/01/2020 20:59:05, Last modified on: 07/01/2020 20:59:05)
+Waits 3 seconds...
+
+Modification of the name of Chewbacca to Chewie
+ 49102173-b82a-4b4d-1d02-08d793b46eb3: Chewie (27/05/1977, 1234567 poils, Inserted on: 07/01/2020 20:59:05, Last modified on: 07/01/2020 20:59:08)
+ ae2ab1fa-ac8d-4df9-1d03-08d793b46eb3: Yoda (21/05/1980, 3 poils, Inserted on: 07/01/2020 20:59:05, Last modified on: 07/01/2020 20:59:05)
+ ccee4eaf-4b50-48ec-1d04-08d793b46eb3: (07/01/2020, 0 poils, Inserted on: 07/01/2020 20:59:05, Last modified on: 07/01/2020 20:59:05)
+
+Display the last Nounours with default values
+Name: ; BirthDate: 07/01/2020 00:00:00; Hair count: 0; Insertion date: 07/01/2020 20:59:05; LastModified: 07/01/2020 20:59:05
+```
+*Notez que la date de modification de Chewie est modifée entre les deux affichages.*
+
+ * **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_007_ValueGeneration.Nounours.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|NULL|01/01/0001 00:00:00|0
+
+*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.*
\ No newline at end of file
diff --git a/p08_BDD_EntityFramework/ex_042_004_ValueGeneration_conventions/ex_042_004_ValueGeneration_conventions.csproj b/p08_BDD_EntityFramework/ex_042_007_ValueGeneration/ex_042_007_ValueGeneration.csproj
similarity index 100%
rename from p08_BDD_EntityFramework/ex_042_004_ValueGeneration_conventions/ex_042_004_ValueGeneration_conventions.csproj
rename to p08_BDD_EntityFramework/ex_042_007_ValueGeneration/ex_042_007_ValueGeneration.csproj