added ex_042_006 et ex_042_007

EFCore3_Reforged
Marc CHEVALDONNE 5 years ago
parent 08fadfa394
commit f2ddc019a7

@ -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}

@ -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 :

@ -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*.

@ -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*.
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_01.png" width="500"/>

@ -27,51 +27,6 @@ namespace ex_042_001_EF_CF_conventions
set;
}
/// <summary>
/// returns a hash code in order to use this class in hash table
/// </summary>
/// <returns>hash code</returns>
public override int GetHashCode()
{
return Nom.GetHashCode();
}
/// <summary>
/// checks if the "right" object is equal to this Nounours or not
/// </summary>
/// <param name="right">the other object to be compared with this Nounours</param>
/// <returns>true if equals, false if not</returns>
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);
}
/// <summary>
/// checks if this Nounours is equal to the other Nounours
/// </summary>
/// <param name="other">the other Nounours to be compared with</param>
/// <returns>true if equals</returns>
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)";

@ -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*.
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_01.png" width="500"/>

@ -37,51 +37,6 @@ namespace ex_042_002_EF_CF_data_annotations
set;
}
/// <summary>
/// returns a hash code in order to use this class in hash table
/// </summary>
/// <returns>hash code</returns>
public override int GetHashCode()
{
return Nom.GetHashCode();
}
/// <summary>
/// checks if the "right" object is equal to this Nounours or not
/// </summary>
/// <param name="right">the other object to be compared with this Nounours</param>
/// <returns>true if equals, false if not</returns>
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);
}
/// <summary>
/// checks if this Nounours is equal to the other Nounours
/// </summary>
/// <param name="other">the other Nounours to be compared with</param>
/// <returns>true if equals</returns>
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)";

@ -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*.
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_01.png" width="500"/>
@ -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*
*Note : les identifiants seront bien sûr différents.*

@ -27,51 +27,6 @@ namespace ex_042_003_EF_CF_Fluent_API
set;
}
/// <summary>
/// returns a hash code in order to use this class in hash table
/// </summary>
/// <returns>hash code</returns>
public override int GetHashCode()
{
return Nom.GetHashCode();
}
/// <summary>
/// checks if the "right" object is equal to this Nounours or not
/// </summary>
/// <param name="right">the other object to be compared with this Nounours</param>
/// <returns>true if equals, false if not</returns>
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);
}
/// <summary>
/// checks if this Nounours is equal to the other Nounours
/// </summary>
/// <param name="other">the other Nounours to be compared with</param>
/// <returns>true if equals</returns>
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)";

@ -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*.
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_01.png" width="500"/>

@ -27,51 +27,6 @@ namespace ex_042_004_Keys_conventions
set;
}
/// <summary>
/// returns a hash code in order to use this class in hash table
/// </summary>
/// <returns>hash code</returns>
public override int GetHashCode()
{
return Nom.GetHashCode();
}
/// <summary>
/// checks if the "right" object is equal to this Nounours or not
/// </summary>
/// <param name="right">the other object to be compared with this Nounours</param>
/// <returns>true if equals, false if not</returns>
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);
}
/// <summary>
/// checks if this Nounours is equal to the other Nounours
/// </summary>
/// <param name="other">the other Nounours to be compared with</param>
/// <returns>true if equals</returns>
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)";

@ -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*.
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_01.png" width="500"/>

@ -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;
}
/// <summary>
/// returns a hash code in order to use this class in hash table
/// </summary>
/// <returns>hash code</returns>
public override int GetHashCode()
{
return Nom.GetHashCode();
}
/// <summary>
/// checks if the "right" object is equal to this Nounours or not
/// </summary>
/// <param name="right">the other object to be compared with this Nounours</param>
/// <returns>true if equals, false if not</returns>
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);
}
/// <summary>
/// checks if this Nounours is equal to the other Nounours
/// </summary>
/// <param name="other">the other Nounours to be compared with</param>
/// <returns>true if equals</returns>
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)";
}
}
}

@ -1,15 +0,0 @@
using Microsoft.EntityFrameworkCore;
namespace ex_042_004_ValueGeneration_conventions
{
class NounoursDBEntities : DbContext
{
public virtual DbSet<Nounours> 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;");
}
}
}

@ -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();
}
}
}

@ -1,175 +0,0 @@
# ex_042_004_ValueGeneration_conventions
*04/01/2020 &sdot; 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*.
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_01.png" width="500"/>
* Déployez dans l'*Explorateur d'objets SQL Server* :
* *SQL Server*,
* puis *(localdb)\MSSQLLocalDB ...*,
* puis *Bases de données*
* puis celle portant le nom de votre migration, dans mon cas : *ex_042_004_ValueGeneration_conventions.Nounours.mdf*
* puis *Tables*
* Faites un clic droit sur la table *dbo.Nounours* puis choisissez *Afficher les données*
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_02.png" width="460"/>
* Vous devriez maintenant pouvoir voir les données suivantes dans le tableau :
|ID |Nom|DateDeNaissance|NbPoils
|---|---|---|---
|1|Chewbacca|27/05/1977 00:00:00|1234567
|2|Yoda|21/05/1980 00:00:00|3
|3|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.*

@ -31,51 +31,6 @@ namespace ex_042_005_Keys_data_annotations
set;
}
/// <summary>
/// returns a hash code in order to use this class in hash table
/// </summary>
/// <returns>hash code</returns>
public override int GetHashCode()
{
return Nom.GetHashCode();
}
/// <summary>
/// checks if the "right" object is equal to this Nounours or not
/// </summary>
/// <param name="right">the other object to be compared with this Nounours</param>
/// <returns>true if equals, false if not</returns>
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);
}
/// <summary>
/// checks if this Nounours is equal to the other Nounours
/// </summary>
/// <param name="other">the other Nounours to be compared with</param>
/// <returns>true if equals</returns>
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)";

@ -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*.
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_01.png" width="500"/>
@ -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*
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_02.png" width="460"/>

@ -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;
}
/// <summary>
/// returns a hash code in order to use this class in hash table
/// </summary>
/// <returns>hash code</returns>
public override int GetHashCode()
{
return Nom.GetHashCode();
}
/// <summary>
/// checks if the "right" object is equal to this Nounours or not
/// </summary>
/// <param name="right">the other object to be compared with this Nounours</param>
/// <returns>true if equals, false if not</returns>
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);
}
/// <summary>
/// checks if this Nounours is equal to the other Nounours
/// </summary>
/// <param name="other">the other Nounours to be compared with</param>
/// <returns>true if equals</returns>
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})";
}
}
}

@ -1,57 +0,0 @@
using Microsoft.EntityFrameworkCore;
namespace ex_042_005_ValueGeneration_data_annotations
{
class NounoursDBEntities : DbContext
{
public virtual DbSet<Nounours> 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";
}
}

@ -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();
}
}
}

@ -1,247 +0,0 @@
# ex_042_005_ValueGeneration_data_annotations
*05/01/2020 &sdot; 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*.
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_01.png" width="500"/>
* Déployez dans l'*Explorateur d'objets SQL Server* :
* *SQL Server*,
* puis *(localdb)\MSSQLLocalDB ...*,
* puis *Bases de données*
* puis celle portant le nom de votre migration, dans mon cas : *ex_042_004_ValueGeneration_conventions.Nounours.mdf*
* puis *Tables*
* Faites un clic droit sur la table *dbo.Nounours* puis choisissez *Afficher les données*
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_02.png" width="460"/>
* Vous devriez maintenant pouvoir voir les données suivantes dans le tableau :
|ID |Nom|DateDeNaissance|NbPoils
|---|---|---|---
|1|Chewbacca|27/05/1977 00:00:00|1234567
|2|Yoda|21/05/1980 00:00:00|3
|3|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.*

@ -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}";
}
}
}

@ -0,0 +1,36 @@
using Microsoft.EntityFrameworkCore;
namespace ex_042_006_Keys_FluentAPI
{
class DBEntities : DbContext
{
public virtual DbSet<Nounours> NounoursSet { get; set; }
public virtual DbSet<Cylon> CylonsSet { get; set; }
public virtual DbSet<Ordinateur> Ordinateurs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ex_042_006_Keys_FluentAPI.Nounours.mdf;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//définition de la clé primaire de Nounours
modelBuilder.Entity<Nounours>().HasKey(n => n.UniqueId);
//définition du mode de génération de la clé : génération à l'insertion
modelBuilder.Entity<Nounours>().Property(n => n.UniqueId).ValueGeneratedOnAdd();
//définition de la clé primaire de Cylon
modelBuilder.Entity<Cylon>().HasKey(c => c.FrakId);
//définition du mode de génération de la clé : génération gérée par l'utilisateur (jamais par la base)
modelBuilder.Entity<Cylon>().Property(c => c.FrakId).ValueGeneratedNever();
//définition d'une clé primaire composite pour Ordinateur
modelBuilder.Entity<Ordinateur>().HasKey(o => new { o.CodeId, o.Modele });
//une clé composite ne peut pas être générée par la base
base.OnModelCreating(modelBuilder);
}
}
}

@ -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)";
}
}
}

@ -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})";
}
}
}

@ -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();
}
}
}

@ -0,0 +1,195 @@
# ex_042_006_Keys_FluentAPI
*07/01/2020 &sdot; 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<Nounours>().HasKey(n => n.UniqueId);
```
```csharp
//définition de la clé primaire de Cylon
modelBuilder.Entity<Cylon>().HasKey(c => c.FrakId);
```
* elle peut être générée par la base et dans ce cas, on ajoute à la ```Property``` la méthode d'extension ```ValueGeneratedOnAdd()```.
```csharp
//définition du mode de génération de la clé : génération à l'insertion
modelBuilder.Entity<Nounours>().Property(n => n.UniqueId).ValueGeneratedOnAdd();
```
* elle peut ne pas être générée par la base et être gérée par l'utilisateur, dans ce cas on utilise la méthode d'extension ```ValueGeneratedNever()```.
Dans ce dernier cas, c'est à l'utilisateur de gérer ses propres clés et leur unicité dans la base.
```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<Cylon>().Property(c => c.FrakId).ValueGeneratedNever();
```
* elle peut être de différents types ```int```, ```string```, ```Guid```, ```byte[]```... attention toutefois si vous choisissez de laisser la table générer les valeurs car certains fournisseurs ne savent pas générer tous les types.
## Les clés primaires composites
En *Fluent API* (et seulement en *Fluent API*), on peut définir des clés composites, c'est-à-dire se basant sur plusieurs propriétés.
Pour cela, on utilise également ```HasKey```et on l'associe à un type anonyme, comme par exemple pour la classe ```Ordinateur``` dans cet exemple, dont la clé est un composite des propriétés ```CodeId``` et ```Modele```.
Ainsi, dans la méthode ```OnModelCreating``` de votre classe dérivant de ```DbContext```, on ajoute :
```csharp
//définition d'une clé primaire composite pour Ordinateur
modelBuilder.Entity<Ordinateur>().HasKey(o => new { o.CodeId, o.Modele });
```
Les clés composites ne peuvent pas être générées par la base.
## Les classes POCO ```Nounours```, ```Cylon``` et ```Ordinateur```
Lorsqu'on utilise la *Fluent API*, ces classes n'ont aucune annotation. La classe ```Ordinateur``` n'a pas de propriété "Id".
## La classe ```DBEntites : DbContext```
La classe dérivant de ```DbContext``` ressemble dès lors dans notre exemple à :
```csharp
using Microsoft.EntityFrameworkCore;
namespace ex_042_006_Keys_FluentAPI
{
class DBEntities : DbContext
{
public virtual DbSet<Nounours> NounoursSet { get; set; }
public virtual DbSet<Cylon> CylonsSet { get; set; }
public virtual DbSet<Ordinateur> Ordinateurs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ex_042_006_Keys_FluentAPI.Nounours.mdf;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//définition de la clé primaire de Nounours
modelBuilder.Entity<Nounours>().HasKey(n => n.UniqueId);
//définition du mode de génération de la clé : génération à l'insertion
modelBuilder.Entity<Nounours>().Property(n => n.UniqueId).ValueGeneratedOnAdd();
//définition de la clé primaire de Cylon
modelBuilder.Entity<Cylon>().HasKey(c => c.FrakId);
//définition du mode de génération de la clé : génération gérée par l'utilisateur (jamais par la base)
modelBuilder.Entity<Cylon>().Property(c => c.FrakId).ValueGeneratedNever();
//définition d'une clé primaire composite pour Ordinateur
modelBuilder.Entity<Ordinateur>().HasKey(o => new { o.CodeId, o.Modele });
//une clé composite ne peut pas être générée par la base
base.OnModelCreating(modelBuilder);
}
}
}
```
## La classe ```Program```
Cette classe est le point d'entrée du programme :
* Elle crée des instances de ```Nounours```, 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*.
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_01.png" width="500"/>
* Déployez dans l'*Explorateur d'objets SQL Server* :
* *SQL Server*,
* puis *(localdb)\MSSQLLocalDB ...*,
* puis *Bases de données*
* puis celle portant le nom de votre migration, dans mon cas : *ex_042_006_Keys_FluentAPI.Nounours.mdf*
* puis *Tables*
* Faites un clic droit sur la table *dbo.Nounours* puis choisissez *Afficher les données*
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_02.png" width="460"/>
* 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.*

@ -7,6 +7,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.0"/>
</ItemGroup>
</Project>

@ -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;
}
/// <summary>
/// returns a hash code in order to use this class in hash table
/// </summary>
/// <returns>hash code</returns>
public override int GetHashCode()
{
return Nom.GetHashCode();
}
/// <summary>
/// checks if the "right" object is equal to this Nounours or not
/// </summary>
/// <param name="right">the other object to be compared with this Nounours</param>
/// <returns>true if equals, false if not</returns>
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);
}
/// <summary>
/// checks if this Nounours is equal to the other Nounours
/// </summary>
/// <param name="other">the other Nounours to be compared with</param>
/// <returns>true if equals</returns>
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})";
}
}
}

@ -1,78 +0,0 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
namespace ex_042_006_ValueGeneration_FluentAPI
{
class NounoursDBEntities : DbContext
{
public virtual DbSet<Nounours> 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<Nounours>().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<Nounours>().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<Nounours>().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<Nounours>().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<Nounours>().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<Nounours>().Ignore(n => n.NbPoils);
modelBuilder.Entity<Nounours>().Property(n => n.InsertionDate)/*.ValueGeneratedOnAdd()*/.HasDefaultValue(DateTime.UtcNow);
modelBuilder.Entity<Nounours>().Property(n => n.LastModified)/*.ValueGeneratedOnAddOrUpdate()*/.HasDefaultValue(DateTime.UtcNow);
//if (this.Database.IsSqlServer())
//{
// modelBuilder.Entity<Nounours>().Property(n => n.InsertionDate).HasDefaultValueSql("getdate()");
// modelBuilder.Entity<Nounours>().Property(n => n.LastModified).HasDefaultValueSql("getdate()");
//}
base.OnModelCreating(modelBuilder);
}
public override int SaveChanges()
{
ChangeTracker.DetectChanges();
foreach (var item in ChangeTracker.Entries<Nounours>().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<Nounours>().Where(e => e.State == EntityState.Modified))
{
item.Property(n => n.LastModified).CurrentValue = DateTime.UtcNow;
}
return base.SaveChanges();
}
}
}

@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.0" />
</ItemGroup>
</Project>

@ -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})";
}
}
}

@ -0,0 +1,44 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
namespace ex_042_007_ValueGeneration
{
class NounoursDBEntities : DbContext
{
public virtual DbSet<Nounours> 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<Nounours>().Property(n => n.Nom).HasDefaultValue("");
modelBuilder.Entity<Nounours>().Property(n => n.DateDeNaissance).HasDefaultValue(DateTime.UtcNow);
modelBuilder.Entity<Nounours>().Property(n => n.DateDInsertion).HasDefaultValue(DateTime.UtcNow);
modelBuilder.Entity<Nounours>().Property(n => n.DernièreModification).HasDefaultValue(DateTime.UtcNow);
base.OnModelCreating(modelBuilder);
}
public override int SaveChanges()
{
ChangeTracker.DetectChanges();
foreach (var item in ChangeTracker.Entries<Nounours>().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<Nounours>().Where(e => e.State == EntityState.Modified))
{
item.Property(n => n.DernièreModification).CurrentValue = DateTime.UtcNow;
}
return base.SaveChanges();
}
}
}

@ -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)

@ -0,0 +1,284 @@
# ex_042_007_ValueGeneration
*07/01/2020 &sdot; 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<Nounours>().Property(n => n.Nom).HasDefaultValue("");
modelBuilder.Entity<Nounours>().Property(n => n.DateDeNaissance).HasDefaultValue(DateTime.UtcNow);
modelBuilder.Entity<Nounours>().Property(n => n.DateDInsertion).HasDefaultValue(DateTime.UtcNow);
modelBuilder.Entity<Nounours>().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<Nounours>().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<Nounours>().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<Nounours>().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<Nounours>().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<Nounours>().Property(n => n.DateDeNaissance).HasDefaultValue(DateTime.UtcNow);
modelBuilder.Entity<Nounours>().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*.
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_01.png" width="500"/>
* Déployez dans l'*Explorateur d'objets SQL Server* :
* *SQL Server*,
* puis *(localdb)\MSSQLLocalDB ...*,
* puis *Bases de données*
* puis celle portant le nom de votre migration, dans mon cas : *ex_042_007_ValueGeneration.Nounours.mdf*
* puis *Tables*
* Faites un clic droit sur la table *dbo.Nounours* puis choisissez *Afficher les données*
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_02.png" width="460"/>
* Vous devriez maintenant pouvoir voir les données suivantes dans le tableau :
|ID |Nom|DateDeNaissance|NbPoils
|---|---|---|---
|1|Chewbacca|27/05/1977 00:00:00|1234567
|2|Yoda|21/05/1980 00:00:00|3
|3|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.*
Loading…
Cancel
Save