added ex_042_009

EFCore3_Reforged
Marc CHEVALDONNE 5 years ago
parent bb305a618c
commit 9941e00b0a

@ -566,6 +566,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_042_008_DataSeeding_befo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_041_004_ConsoleTests_w_SQLite", "p08_BDD_EntityFramework\ex_041_004_ConsoleTests_w_SQLite\ex_041_004_ConsoleTests_w_SQLite.csproj", "{2249C4B0-563D-44C8-AAA5-C8366A8F509C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_042_009_DataSeeding", "p08_BDD_EntityFramework\ex_042_009_DataSeeding\ex_042_009_DataSeeding.csproj", "{B5CEC904-1475-4215-A20A-01BDD219AE25}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -4702,6 +4704,26 @@ Global
{2249C4B0-563D-44C8-AAA5-C8366A8F509C}.Release|x64.Build.0 = Release|Any CPU
{2249C4B0-563D-44C8-AAA5-C8366A8F509C}.Release|x86.ActiveCfg = Release|Any CPU
{2249C4B0-563D-44C8-AAA5-C8366A8F509C}.Release|x86.Build.0 = Release|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Debug|ARM.ActiveCfg = Debug|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Debug|ARM.Build.0 = Debug|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Debug|ARM64.Build.0 = Debug|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Debug|x64.ActiveCfg = Debug|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Debug|x64.Build.0 = Debug|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Debug|x86.ActiveCfg = Debug|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Debug|x86.Build.0 = Debug|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Release|Any CPU.Build.0 = Release|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Release|ARM.ActiveCfg = Release|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Release|ARM.Build.0 = Release|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Release|ARM64.ActiveCfg = Release|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Release|ARM64.Build.0 = Release|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Release|x64.ActiveCfg = Release|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Release|x64.Build.0 = Release|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Release|x86.ActiveCfg = Release|Any CPU
{B5CEC904-1475-4215-A20A-01BDD219AE25}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -4970,6 +4992,7 @@ Global
{78374D80-5BE7-425D-BE62-AD8F26491112} = {55E00151-58A6-4E7D-9457-0BB8213B82F5}
{26B0F58C-3373-4965-A00A-FB9F9AA2DFC5} = {78374D80-5BE7-425D-BE62-AD8F26491112}
{2249C4B0-563D-44C8-AAA5-C8366A8F509C} = {56C5A51B-16E9-4F93-9C32-8F91710391E8}
{B5CEC904-1475-4215-A20A-01BDD219AE25} = {78374D80-5BE7-425D-BE62-AD8F26491112}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8D31C3AE-36FF-4667-A2A7-0E670245A59E}

@ -7,10 +7,12 @@
Lorsqu'on cherche à tester notre code et nos accès à la base de données, on n'a pas nécessairement envie de créer la base juste pour les tests.
Pour cela, il existe des solutions et des fournisseurs permettant de tester les bases sans avoir à réellement les créer :
* le fournisseur **InMemory** permet ceci mais de manière approximative, car **InMemory** n'est pas une base de données relationnelle : il y a donc des limitations.
* **SQLite** possède un mode *In-Memory* qui lui, permet de tester une base de données relationnelle, sans avoir à créer une base de données.
* **SQLite** possède un mode *In-Memory* qui lui, permet de tester une base de données relationnelle, sans avoir à créer une base de données.
**Je conseille donc l'utilisation de _SQL in Memory_ plutôt que InMemory, puisqu'il permet de tester une base relationnelle.**
Cet exemple montre comment utiliser **InMemory** et **SQLite in-memory** à travers une injection de dépendance. En d'autres termes, vous continuez à définir votre chaîne de connexion sur une base de données, mais vous permettez néanmoins l'utilisation, à la demande, de **InMemory** pour des tests.
Puisque ce fournisseur devient intéressant dans le cas de tests, j'ai donc ajouté un 2ème projet lié à cet exemple, permettant d'avoir accès à des tests unitaires utilisant **InMemory** ou de **SQLite in-memory**.
Puisque ce fournisseur devient intéressant dans le cas de tests, j'ai donc ajouté un 2ème projet lié à cet exemple, permettant d'avoir accès à des tests unitaires utilisant **InMemory** ou **SQLite in-memory**.
Pour le reste de l'exemple, celui-ci n'apporte rien de nouveau par rapport à l'exemple ex_041_001 concernant l'utilisation d'**Entity Framework Core**.
---

@ -10,7 +10,7 @@ Il est conseillé d'utiliser une méthode plus moderne (cf. ex_042_009_DataSeedi
## Comment est construit cet exemple ?
* Le projet est de type .NET Core
* Il contient deux classes :
* Il contient trois classes :
* ```Nounours```
* ```NounoursDBEntities```
* ```DataSeeder```

@ -0,0 +1,45 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ex_042_009_DataSeeding
{
[Table("TableNounours")]
public class Nounours
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid UniqueId
{
get; set;
}
[Required]
[MaxLength(256)]
//[Column("name", Order=0, TypeName ="varchar(200)")]
public string Nom
{
get;
set;
}
[Column("Naissance", TypeName = "date")]
public DateTime DateDeNaissance
{
get;
set;
}
public int NbPoils
{
get;
set;
}
public override string ToString()
{
return $"{UniqueId}: {Nom} ({DateDeNaissance:dd/MM/yyyy}, {NbPoils} poils)";
}
}
}

@ -0,0 +1,14 @@
using Microsoft.EntityFrameworkCore;
namespace ex_042_009_DataSeeding
{
class NounoursDBEntities : DbContext
{
public virtual DbSet<Nounours> NounoursSet { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ex_042_009_DataSeeding.Nounours.mdf;Trusted_Connection=True;");
}
}
}

@ -0,0 +1,19 @@
using Microsoft.EntityFrameworkCore;
using System;
namespace ex_042_009_DataSeeding
{
class NounoursDBEntitiesWithStub : NounoursDBEntities
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Nounours>().HasData(
new Nounours { UniqueId = Guid.Parse("{4422C524-B2CB-43EF-8263-990C3CEA7CAE}"), Nom = "Chewbacca", DateDeNaissance = new DateTime(1977, 5, 27), NbPoils = 1234567 },
new Nounours { UniqueId = Guid.Parse("{A4F84D92-C20F-4F2D-B3F9-CA00EF556E72}"), Nom = "Yoda", DateDeNaissance = new DateTime(1980, 5, 21), NbPoils = 3 },
new Nounours { UniqueId = Guid.Parse("{AE5FE535-F041-445E-B570-28B75BC78CB9}"), Nom = "Ewok", DateDeNaissance = new DateTime(1983, 5, 25), NbPoils = 3456789 }
);
}
}
}

@ -0,0 +1,35 @@
using Microsoft.Data.SqlClient;
using System;
using System.Linq;
using static System.Console;
namespace ex_042_009_DataSeeding
{
class Program
{
static void Main(string[] args)
{
OutputEncoding = System.Text.Encoding.UTF8;
try
{
using (NounoursDBEntities db = new NounoursDBEntitiesWithStub())
{
WriteLine("Contenu de la base :");
foreach (var n in db.NounoursSet)
{
WriteLine($"\t{n}");
}
}
}
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,117 @@
# ex_042_009_DataSeeding
*13/01/2020 &sdot; Marc Chevaldonné*
---
Cet exemple montre comment il est recommandé d'utiliser du Stub avec Entity Framework Core depuis la version 2.1.
---
## Comment est construit cet exemple ?
* Le projet est de type .NET Core
* Il contient trois classes :
* ```Nounours```
* ```NounoursDBEntities```
* ```NounoursDBEntitiesWithStub```
Le contenu des classes ```Nounours``` et ```NounoursDBEntities``` correspond à ce qui a été vu dans les exemples précédents. Seule la classe ```NounoursDBEntitiesWithStub``` sera donc expliquée ici.
### La classe ```NounoursDBEntitiesWithStub```
* ```NounoursDBEntitiesWithStub``` est une classe fille de ```NounoursDBEntites```.
Son rôle est de proposer un Stub en plus de ce que sait déjà faire sa classe mère. Elle ne sera donc utilisée que pour des tests unitaires ou fonctionnels.
En conséquence, elle reprend tout ce que fait sa classe mère et ne change que la méthode ```OnModelCreating``` qui appelle la méthode de la classe mère puis ajoute des instances d'entités, grâce à la méthode d'extension ```HasData```.
```csharp
using Microsoft.EntityFrameworkCore;
using System;
namespace ex_042_009_DataSeeding
{
class NounoursDBEntitiesWithStub : NounoursDBEntities
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Nounours>().HasData(
new Nounours { UniqueId = Guid.Parse("{4422C524-B2CB-43EF-8263-990C3CEA7CAE}"), Nom = "Chewbacca", DateDeNaissance = new DateTime(1977, 5, 27), NbPoils = 1234567 },
new Nounours { UniqueId = Guid.Parse("{A4F84D92-C20F-4F2D-B3F9-CA00EF556E72}"), Nom = "Yoda", DateDeNaissance = new DateTime(1980, 5, 21), NbPoils = 3 },
new Nounours { UniqueId = Guid.Parse("{AE5FE535-F041-445E-B570-28B75BC78CB9}"), Nom = "Ewok", DateDeNaissance = new DateTime(1983, 5, 25), NbPoils = 3456789 }
);
}
}
}
```
* __Note importante__ : remarquez que la création des instances d'entités donne aussi l'```UniqueId``` puisqu'il ne s'agit pas d'un ajout "classique" dans la base mais la table est créée avec ces instances.
* __Note importante__ : l'utilisation de ```UniqueId``` vous permettra d'ajouter des entités liées dans le Stub.
* __Explication__ : l'utilisaiton de ```HasData``` dans ```OnModelCreating``` fait que vos données stubbées feront parties de la migration : rien à voir avec un ajout depuis votre appli consommatrice.
* __Note__ : souvent, on en profite pour réécrire également ```OnConfiguring``` afin de changer de fournisseur (pour prendre par exemple un *SQLite in memory* puisque ce contexte stubbé est voué à être utilisé par des tests).
* Elle est ensuite utilisée dans ```Program``` pour remplir la base de manière tout à fait classique et ne nécessite aucun appel supplémentaire.
```csharp
using (NounoursDBEntities db = new NounoursDBEntitiesWithStub())
{
WriteLine("Contenu de la base :");
foreach (var n in db.NounoursSet)
{
WriteLine($"\t{n}");
}
}
```
## Comment exécuter cet exemple ?
Pour tester cette application, n'oubliez pas les commandes comme présentées dans l'exemple ex_041_001 : pour générer l'exemple, il vous faut d'abord préparer les migrations et les tables.
* Ouvrez la *Console du Gestionnaire de package*, pour cela, dirigez-vous dans le menu *Outils*, puis *Gestionnaire de package NuGet*, puis *Console du Gestionnaire de package*.
* Dans la console que vous venez d'ouvrir, déplacez-vous dans le dossier du projet .NET Core, ici :
```
cd .\p08_BDD_EntityFramework\ex_042_009_DataSeeding
```
*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_009
```
* 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_009_DataSeeding**.
* Le résultat de l'exécution va ressembler à :
```
Contenu de la base :
ae5fe535-f041-445e-b570-28b75bc78cb9: Ewok (25/05/1983, 3456789 poils)
4422c524-b2cb-43ef-8263-990c3cea7cae: Chewbacca (27/05/1977, 1234567 poils)
a4f84d92-c20f-4f2d-b3f9-ca00ef556e72: Yoda (21/05/1980, 3 poils)
```
* 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_009_DataSeeding.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 :
|UniqueId |Nom|Naissance|NbPoils
|---|---|---|---
|ae5fe535-f041-445e-b570-28b75bc78cb9|Ewok|25/05/1983|3456789
|4422c524-b2cb-43ef-8263-990c3cea7cae|Chewbacca|27/05/1977|1234567
|a4f84d92-c20f-4f2d-b3f9-ca00ef556e72|Yoda|21/05/1980|3

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