added samples ex_042_001

EFCore3_Reforged
Marc CHEVALDONNE 5 years ago
parent 52b9f5eab6
commit 785d53798c

@ -550,9 +550,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_041_004_TestingInMemory"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_041_004_UnitTests_w_InMemory", "p08_BDD_EntityFramework\ex_041_004_UnitTests_w_InMemory\ex_041_004_UnitTests_w_InMemory.csproj", "{8C4BC92E-2E7D-4447-805F-0BCAF986022E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ex_041_004_ConsoleTests_w_SqlServer", "p08_BDD_EntityFramework\ex_041_004_ConsoleTests_w_SqlServer\ex_041_004_ConsoleTests_w_SqlServer.csproj", "{4AE5E57F-2D9B-40BD-B1C3-B39AE756172C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_041_004_ConsoleTests_w_SqlServer", "p08_BDD_EntityFramework\ex_041_004_ConsoleTests_w_SqlServer\ex_041_004_ConsoleTests_w_SqlServer.csproj", "{4AE5E57F-2D9B-40BD-B1C3-B39AE756172C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ex_041_004_UnitTests_w_SQLiteInMemory", "p08_BDD_EntityFramework\ex_041_004_UnitTests_w_SQLiteInMemory\ex_041_004_UnitTests_w_SQLiteInMemory.csproj", "{2BE75812-1DC2-4E9A-8D99-99456F11AB0D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_041_004_UnitTests_w_SQLiteInMemory", "p08_BDD_EntityFramework\ex_041_004_UnitTests_w_SQLiteInMemory\ex_041_004_UnitTests_w_SQLiteInMemory.csproj", "{2BE75812-1DC2-4E9A-8D99-99456F11AB0D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "chap042_EF_Creating_Model", "chap042_EF_Creating_Model", "{55E00151-58A6-4E7D-9457-0BB8213B82F5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "01. EF CodeFirst approach", "01. EF CodeFirst approach", "{FC04E822-7560-4C80-9E59-C03DB40E9F17}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ex_042_001_EF_CF_conventions", "p08_BDD_EntityFramework\ex_042_001_EF_CF_conventions\ex_042_001_EF_CF_conventions.csproj", "{1566457E-6D28-412C-86A3-95E8821B2DDD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ex_042_002_EF_CF_data_annotations", "p08_BDD_EntityFramework\ex_042_002_EF_CF_data_annotations\ex_042_002_EF_CF_data_annotations.csproj", "{568486B5-85E4-4F86-B86C-A373B5F471FD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ex_042_003_EF_CF_Fluent_API", "p08_BDD_EntityFramework\ex_042_003_EF_CF_Fluent_API\ex_042_003_EF_CF_Fluent_API.csproj", "{9D444878-F974-4883-9023-1A46E80ADFF1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -4610,6 +4620,66 @@ Global
{2BE75812-1DC2-4E9A-8D99-99456F11AB0D}.Release|x64.Build.0 = Release|Any CPU
{2BE75812-1DC2-4E9A-8D99-99456F11AB0D}.Release|x86.ActiveCfg = Release|Any CPU
{2BE75812-1DC2-4E9A-8D99-99456F11AB0D}.Release|x86.Build.0 = Release|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Debug|ARM.ActiveCfg = Debug|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Debug|ARM.Build.0 = Debug|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Debug|ARM64.Build.0 = Debug|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Debug|x64.ActiveCfg = Debug|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Debug|x64.Build.0 = Debug|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Debug|x86.ActiveCfg = Debug|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Debug|x86.Build.0 = Debug|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Release|Any CPU.Build.0 = Release|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Release|ARM.ActiveCfg = Release|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Release|ARM.Build.0 = Release|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Release|ARM64.ActiveCfg = Release|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Release|ARM64.Build.0 = Release|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Release|x64.ActiveCfg = Release|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Release|x64.Build.0 = Release|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Release|x86.ActiveCfg = Release|Any CPU
{1566457E-6D28-412C-86A3-95E8821B2DDD}.Release|x86.Build.0 = Release|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Debug|ARM.ActiveCfg = Debug|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Debug|ARM.Build.0 = Debug|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Debug|ARM64.Build.0 = Debug|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Debug|x64.ActiveCfg = Debug|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Debug|x64.Build.0 = Debug|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Debug|x86.ActiveCfg = Debug|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Debug|x86.Build.0 = Debug|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Release|Any CPU.Build.0 = Release|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Release|ARM.ActiveCfg = Release|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Release|ARM.Build.0 = Release|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Release|ARM64.ActiveCfg = Release|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Release|ARM64.Build.0 = Release|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Release|x64.ActiveCfg = Release|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Release|x64.Build.0 = Release|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Release|x86.ActiveCfg = Release|Any CPU
{568486B5-85E4-4F86-B86C-A373B5F471FD}.Release|x86.Build.0 = Release|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Debug|ARM.ActiveCfg = Debug|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Debug|ARM.Build.0 = Debug|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Debug|ARM64.Build.0 = Debug|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Debug|x64.ActiveCfg = Debug|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Debug|x64.Build.0 = Debug|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Debug|x86.ActiveCfg = Debug|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Debug|x86.Build.0 = Debug|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Release|Any CPU.Build.0 = Release|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Release|ARM.ActiveCfg = Release|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Release|ARM.Build.0 = Release|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Release|ARM64.ActiveCfg = Release|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Release|ARM64.Build.0 = Release|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Release|x64.ActiveCfg = Release|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Release|x64.Build.0 = Release|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Release|x86.ActiveCfg = Release|Any CPU
{9D444878-F974-4883-9023-1A46E80ADFF1}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -4872,6 +4942,11 @@ Global
{8C4BC92E-2E7D-4447-805F-0BCAF986022E} = {56C5A51B-16E9-4F93-9C32-8F91710391E8}
{4AE5E57F-2D9B-40BD-B1C3-B39AE756172C} = {56C5A51B-16E9-4F93-9C32-8F91710391E8}
{2BE75812-1DC2-4E9A-8D99-99456F11AB0D} = {56C5A51B-16E9-4F93-9C32-8F91710391E8}
{55E00151-58A6-4E7D-9457-0BB8213B82F5} = {65DF0C9A-4F06-4361-8DD9-E8360B6325CA}
{FC04E822-7560-4C80-9E59-C03DB40E9F17} = {55E00151-58A6-4E7D-9457-0BB8213B82F5}
{1566457E-6D28-412C-86A3-95E8821B2DDD} = {FC04E822-7560-4C80-9E59-C03DB40E9F17}
{568486B5-85E4-4F86-B86C-A373B5F471FD} = {FC04E822-7560-4C80-9E59-C03DB40E9F17}
{9D444878-F974-4883-9023-1A46E80ADFF1} = {FC04E822-7560-4C80-9E59-C03DB40E9F17}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8D31C3AE-36FF-4667-A2A7-0E670245A59E}

@ -1,5 +1,5 @@
# Entity Framework Core 3.0
*31/12/2019 ⋅ Marc Chevaldonné*
*02/01/2020 ⋅ Marc Chevaldonné*
---
Entity Framework (EF) Core est un ORM (Object-Relational Mapper) qui permet aux développeurs .NET de gérer de manière simple, légère et extensible, des bases de données.
@ -17,6 +17,7 @@ Les exemples sont organis
Dans cette partie, je donnerai quelques notions pour se connecter à une base à l'aide de chaîne de connection (*connection strings*), comment utiliser des *providers de tests...*.
Il s'agira en conséquence d'exemples simples manquants d'explications sur certains points, car ils seront présentés plus tard.
* **ex_041_001 : Connection Strings** : montre comment utiliser une chaîne de connexion SQL Server ou SQLite.
* **ex_041_004 : Testing in memory** : présente comment utiliser des fournisseurs en mémoire pour éviter la surchage de la création d'une base de données en particulier dans le cas de tests unitaires. Cet exemple est composé de 4 projets.
2. *Model* :
Ce chapitre s'attardera sur le lien entre le modèle et la base de données. En effet, avec EF, l'accès aux données se fait via le modèle, c'est-à-dire l'ensemble de vos classes (qui seront reliées à des tables créées plus ou moins automatiquement)
ainsi qu'un contexte (```DbContext```) qui représentera une session de connexion avec votre (ou vos) base(s) de données.

@ -1,5 +1,5 @@
# ex_041_004_TestingInMemory
*01/01/2020 ⋅ Marc Chevaldonné*
*02/01/2020 ⋅ Marc Chevaldonné*
---

@ -0,0 +1,81 @@
using System;
namespace ex_042_001_EF_CF_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)";
}
}
}

@ -0,0 +1,15 @@
using Microsoft.EntityFrameworkCore;
namespace ex_042_001_EF_CF_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_001_EF_CF_conventions.Nounours.mdf;Trusted_Connection=True;");
}
}
}

@ -0,0 +1,70 @@
using Microsoft.Data.SqlClient;
using System;
using System.Linq;
using static System.Console;
namespace ex_042_001_EF_CF_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 { Nom = "Ewok", DateDeNaissance = new DateTime(1983, 5, 25), NbPoils = 3456789 };
try
{
using (NounoursDBEntities db = new NounoursDBEntities())
{
if (db.NounoursSet.Count() > 0)
{
WriteLine("La base n'est pas vide !");
foreach (var n in db.NounoursSet)
{
WriteLine($"\t{n}");
}
WriteLine("début du nettoyage...");
foreach (var n in db.NounoursSet)
{
WriteLine($"Suppression de {n}");
db.NounoursSet.Remove(n);
}
WriteLine("Base avant sauvegarde des changements :");
foreach (var n in db.NounoursSet)
{
WriteLine($"\t{n}");
}
db.SaveChanges();
WriteLine("Base après sauvegarde des changements :");
foreach (var n in db.NounoursSet)
{
WriteLine($"\t{n}");
}
}
db.NounoursSet.AddRange(new Nounours[] { chewie, yoda, ewok });
db.SaveChanges();
WriteLine("Base après ajout des 3 nounours et sauvegarde des changements :");
foreach (var n in db.NounoursSet)
{
WriteLine($"\t{n}");
}
}
}
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,211 @@
# ex_042_001_EF_CF_conventions
*02/01/2020 &sdot; Marc Chevaldonné*
---
Le lien entre une base de données et vos classes à l'aide de **Entity Framework Core** se fait via une classe dérivant de ```DbContext```.
Cette classe doit contenir des ```DbSet<T>```. Chaque ```DbSet<T>``` correspond à une table et ```T``` correspond à une de vos classes qu'on appelle *entité*.
Le lien entre les tables et les entités est géré plus ou moins automatiquement par le *framework*.
**EF Core** permet de lire/écrire les instances d'entité de la base de données ; permet de créer des tables pour les entités via les migrations (pour les bases de données relationnelles) ;
les types exposés dans les propriétés d'une entité deviennent automatiquement des entités (mais pas forcément des tables)
**Entity Framework Core** propose 3 solutions différentes pour relier des entités à des tables de la base de données :
* **conventions d'écriture** : c'est la solution la plus simple, qui analyse le code de votre classe pour en déduire de quelle manière la relier à la table.
* **data annotations** : elle se base sur des décorateurs (appelés *data annotations*) que vous placez autour de vos propriétés pour indiquer de quelle manière les relier aux colonnes de votre table. Les *data annotations* écrasent les conventions d'écriture.
* **Fluent API** : directement dans le code de votre ```DbContext``` (plus précisément, dans la méthode ```OnModelCreating```), vous précisez comment se fait le *mapping* entre votre entité et votre table. La *Fluent API* écrase les conventions d'écriture et les *data annotations*.
En d'autres termes, si vous n'écrivez rien, **EF Core** utilise les conventions d'écriture ; si vous n'utilisez que des *data annotations*, elles sont prioritaires sur les convetions d'écriture ; si vous utilisez la *Fluent API*, elle est prioritaire sur les deux autres méthodes.
Mais on peut faire un mix des différentes méthodes.
Cet exemple montre de quelle manière les **conventions d'écriture** sont utilisées pour transformer une entité en table.
Il montre notamment :
* comment le nom de la table est choisi
* s'il est possible d'ignorer une propriété de l'entité
* comment le nom et le type d'une colonne de la table sont choisis
* comment un identifiant unique est choisi et généré.
Cet exemple est répété d'une manière très similaire en utilisant les autres méthodes de *mapping* entre entité et table :
* **ex_042_002_EF_CF_data_annotations** : avec les *data annotations*
* **ex_042_003_EF_CF_Fluent_API** : avec la *Fluent API*
---
## Comment est construit cet exemple ?
* Le projet est de type .NET Core
* Il contient deux classes :
* ```Nounours```
* ```NounoursDBEntities```
### La classe ```NounoursDBEntities```
* Cette classe dérive de ```DbContext```. Elle contient des ```DbSet<T>``` où ```T``` est une entité. Elle contient autant de ```DbSet<T>``` que de tables.
```csharp
class NounoursDBEntities : DbContext
{
public virtual DbSet<Nounours> NounoursSet { get; set; }
}
```
ici, on indique donc qu'il y aura une table de ```Nounours```.
* **EF Core** utilisera cette classe pour faire la création de la base de données et de ses tables. Pour cela, elle utilise la chaîne de connexion donnée dans la méthode ```OnConfiguring```.
```csharp
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ex_042_001_EF_CF_conventions.Nounours.mdf;Trusted_Connection=True;");
}
```
=> cf **ex_041_001_ConnectionStrings** pour en savoir plus sur les chaîne de connexion
* Dans cet exemple, la table de ```Nounours``` est créée en utilisant les conventions d'écriture de la classe ```Nounours```.
### La classe ```Nounours```
* ```Nounours``` est une entité, on parle aussi de classe POCO, i.e. Plain Old CLR Object.
```csharp
public class Nounours
{
public int ID
{
get; set;
}
public string Nom
{
get;
set;
}
public DateTime DateDeNaissance
{
get;
set;
}
public int NbPoils
{
get;
set;
}
}
```
* Elle contient 3 propriétés en lecture/écriture : ```Nom```, ```DateDeNaissance``` et ```NbPoils```. Nous parlerons de la 4ème (```ID```) dans un moment.
* **Entity Framework Core** va utiliser la classe POCO ```Nounours``` pour créer une table dans la base de données, lorsque le ```DbSet``` va être créé.
* L'utilisation des conventions d'écriture d'Entity Framework font que la table qui va être créée aura :
* un nom correspondant au nom de la classe POCO : ici "Nounours"
* une colonne pour chaque propriété publique : ici, "Nom", "DateDeNaissance" et "NbPoils"
* De plus, en rajoutant une propriété de type int et avec le nom "ID", Entity Framework ajoute directement une colonne "ID" et l'utilise comme clé primaire.
**En résumé** :
* le nom de la table est choisi automatiquement (c'est le nom de l'entité)
* toutes les propriétés ayant un getter et un setter publiques sont des colonnes de la table
* le nom des colonnes est choisi automatiquement (il s'agit du nom des propriétés)
* il n'est pas possible d'ignorer une propriété
* le type d'une colonne est imposé par un *mapping* automatique entre les types .NET et ceux de la base de données. Par exemple :
* un ```DateTime``` est transformé en ```datetime2(7)```
* un ```string``` est transformé en ```nvarchar(max)```
* si c'est une clé, elle est transformée en ```nvarchar(450)```
* ...
* si la classe possède une propriété de type ```int``` s'appelant ```ID```, elle est automatiquement utilisée comme clé primaire générée par lz base de données lors de l'insertion
### La classe ```Program```
Cette classe est le point d'entrée du programme :
* Elle crée des instances de ```Nounours```
```csharp
Nounours chewie = new Nounours { Nom = "Chewbacca", DateDeNaissance = new DateTime(1977, 5, 27), NbPoils = 1234567 };
Nounours yoda = new Nounours { Nom = "Yoda", DateDeNaissance = new DateTime(1980, 5, 21), NbPoils = 3 };
Nounours ewok = new Nounours { Nom = "Ewok", DateDeNaissance = new DateTime(1983, 5, 25), NbPoils = 3456789 };
```
* Elle démarre une connexion à la base de données
```csharp
using (NounoursDBEntities db = new NounoursDBEntities())
{
//...
}
```
* Elle vérifie si la table est vide, et si ce n'est pas le cas, elle la vide.
Notez l'accès à la table de ```Nounours``` via ```db.NounoursSet```.
Notez également que tant que ```SaveChanges``` n'est pas appelée, les suppressions ne sont pas effectives dans la base, seulement en local dans le programme.
_Cette partie de l'exemple ne s'exécutera que si la base existe déjà, par exemple lors d'une deuxième exécution._
```csharp
if (db.NounoursSet.Count() > 0)
{
WriteLine("La base n'est pas vide !");
foreach (var n in db.NounoursSet)
{
WriteLine($"\t{n}");
}
WriteLine("début du nettoyage...");
foreach (var n in db.NounoursSet.ToArray())
{
WriteLine($"Suppression de {n}");
db.NounoursSet.Remove(n);
}
WriteLine("Base avant sauvegarde des changements :");
foreach (var n in db.NounoursSet)
{
WriteLine($"\t{n}");
}
db.SaveChanges();
WriteLine("Base après sauvegarde des changements :");
foreach (var n in db.NounoursSet)
{
WriteLine($"\t{n}");
}
}
```
* Elle ajoute ensuite les ```Nounours```et sauvegarde les changements pour que ceux-ci soit effectivement ajoutés à la base.
```csharp
db.NounoursSet.AddRange(new Nounours[] { chewie, yoda, ewok });
db.SaveChanges();
WriteLine("Base après ajout des 3 nounours et sauvegarde des changements :");
foreach (var n in db.NounoursSet)
{
WriteLine($"\t{n}");
}
```
## Comment exécuter cet exemple ?
Pour tester cette application, n'oubliez pas les commandes comme présentées dans l'exemple ex_041_001 : pour générer l'exemple, il vous faut d'abord préparer les migrations et les tables.
* Ouvrez la *Console du Gestionnaire de package*, pour cela, dirigez-vous dans le menu *Outils*, puis *Gestionnaire de package NuGet*, puis *Console du Gestionnaire de package*.
* Dans la console que vous venez d'ouvrir, déplacez-vous dans le dossier du projet .NET Core, ici :
```
cd .\p08_BDD_EntityFramework\ex_042_001_EF_CF_conventions
```
*Note*:
si vous n'avez pas installé correctement EntityFrameworkCore, il vous faudra peut-être utiliser également :
```dotnet tool install --global dotnet-ef```
* Migration :
```
dotnet ef migrations add migration_ex_042_001
```
* Création de la table :
```
dotnet ef database update
```
* Génération et exécution
Vous pouvez maintenant générer et exécuter l'exemple **ex_042_001_EF_CF_conventions**.
* Comment vérifier le contenu des bases de données SQL Server et SQLite ?
Vous pouvez vérifier le contenu de votre base en utilisant l'*Explorateur d'objets SQL Server*.
* Pour cela, allez dans le menu *Affichage* puis *Explorateur d'objets SQL Server*.
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_01.png" width="500"/>
* Déployez dans l'*Explorateur d'objets SQL Server* :
* *SQL Server*,
* puis *(localdb)\MSSQLLocalDB ...*,
* puis *Bases de données*
* puis celle portant le nom de votre migration, dans mon cas : *ex_042_001_EF_CF_conventions.NounoursSet.mdf*
* puis *Tables*
* Faites un clic droit sur la table *dbo.Nounours* puis choisissez *Afficher les données*
<img src="../ex_041_001_ConnectionStrings/readmefiles/sqlserver_02.png" width="460"/>
* Vous devriez maintenant pouvoir voir les données suivantes dans le tableau :
|ID |Nom|DateDeNaissance|NbPoils
|---|---|---|---
|1|Chewbacca|27/05/1977 00:00:00|1234567
|2|Yoda|21/05/1980 00:00:00|3
|3|Ewok|25/05/1983 00:00:00|3456789
*Note: les identifiants peuvent varier en fonction du nombre d'exécution de l'exemple depuis la création de la base de données.*

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</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,12 @@
using System;
namespace ex_042_002_EF_CF_data_annotations
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</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,12 @@
using System;
namespace ex_042_003_EF_CF_Fluent_API
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</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>

@ -4,9 +4,9 @@
* V 001 exemple avec une connection string dans OnConfiguring
* ? 002 exemple avec une connection string dans AppConfig ou équivalent ?
* ? 003 le même avec SecretManager pour les mots de passe ?
* ? 006 connection resiliency ?
* testing
* 005 SQLite in memory
* ? 005 connection resiliency ?
* V testing
* V 004 SQLite in memory
* V 004 InMemory
* ? configuring a dbcontext ?
* ? nullable reference types => navigating (include, theninclude)
@ -28,17 +28,17 @@
* TPH
* discriminator configuration
* shared columns
* sequences?
* ? sequences?
* value conversion
* entity type constructors
* table splitting and table sharing?, owned types?
* keyless entity types?
* alternating model with same DbContext?
* spatial data?
* ? table splitting and table sharing?, owned types?
* ? keyless entity types?
* ? alternating model with same DbContext?
* ? spatial data?
##### managing database schemas + migrations (43)
* migrations
* create and drop APIs
* reverse engineering?
* ? reverse engineering?
##### querying data: LINQ to SQL (44)
* loading all entity, loading a single entity, filtering
* client vs. server evaluation
@ -48,21 +48,21 @@
* eager loading
* explicit loading
* lazy loading
* related data and serialization?
* asynchronous queries?
* raw sql queries?
* global query filters?
* query tags?
* ? related data and serialization?
* ? asynchronous queries?
* ? raw sql queries?
* ? global query filters?
* ? query tags?
* how queries work
##### saving data (44)
* basic save (adding, removing, updating, multiple changes)
* related data (a graph of new entities, a related entity, changing or removing relationships)
* cascade delete
* concurrency conflicts
* transactions
* asynchronous saving?
* disconnected entities?
* setting explicit values for generated properties?
* transactions (TransactionScope ?)
* ? asynchronous saving?
* ? disconnected entities?
* ? setting explicit values for generated properties?
##### database providers (45)
* microsoft sql server
* sqlite

Loading…
Cancel
Save