From 35fe2b64554cb8018c3868086318f39c570ad42c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Chevaldonn=C3=A9?= Date: Tue, 21 Jan 2020 00:18:12 +0100 Subject: [PATCH] ended ex_042_013 --- Exemples.sln | 25 +--- .../CarnetDeSante.cs | 42 ------- .../DbContextInitializer.cs | 79 ------------ .../Nounours.cs | 98 --------------- .../NounoursDBEntities.cs | 66 ---------- .../Program.cs | 75 ------------ ..._042_007_EF_CF_One_to_One_FluentAPI.csproj | 21 ---- p08_BDD_EntityFramework/ReadMe.md | 7 +- .../NounoursDBEntities.cs | 1 - .../ex_042_013_OneToOne_FluentAPI/Program.cs | 2 +- .../ex_042_013_OneToOne_FluentAPI/ReadMe.md | 115 ++++++++++++++---- p08_BDD_EntityFramework/temp.md | 2 +- 12 files changed, 95 insertions(+), 438 deletions(-) delete mode 100644 ex_042_007_EF_CF_One_to_One_FluentAPI/CarnetDeSante.cs delete mode 100644 ex_042_007_EF_CF_One_to_One_FluentAPI/DbContextInitializer.cs delete mode 100644 ex_042_007_EF_CF_One_to_One_FluentAPI/Nounours.cs delete mode 100644 ex_042_007_EF_CF_One_to_One_FluentAPI/NounoursDBEntities.cs delete mode 100644 ex_042_007_EF_CF_One_to_One_FluentAPI/Program.cs delete mode 100644 ex_042_007_EF_CF_One_to_One_FluentAPI/ex_042_007_EF_CF_One_to_One_FluentAPI.csproj diff --git a/Exemples.sln b/Exemples.sln index 06f35b0..8f55aa8 100644 --- a/Exemples.sln +++ b/Exemples.sln @@ -413,8 +413,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_039_002_LINQ_to_XML", "e EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_040_001_LINQ_to_Json", "ex_040_001_LINQ_to_Json\ex_040_001_LINQ_to_Json.csproj", "{B506ECD8-853D-4E69-8F0A-AFCDB7FEABF3}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_042_007_EF_CF_One_to_One_FluentAPI", "ex_042_007_EF_CF_One_to_One_FluentAPI\ex_042_007_EF_CF_One_to_One_FluentAPI.csproj", "{4D079A62-B303-4900-BEC1-994BC26BCCA2}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_042_008_EF_CF_One_to_Many", "ex_042_008_EF_CF_One_to_Many\ex_042_008_EF_CF_One_to_Many.csproj", "{91FD20B6-250C-437B-9FBE-DA4D2B87DE03}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_042_009_EF_CF_One_to_Many_FluentAPI", "ex_042_009_EF_CF_One_to_Many_FluentAPI\ex_042_009_EF_CF_One_to_Many_FluentAPI.csproj", "{2C53F069-6E87-4A36-8915-E0219EBA8BA7}" @@ -580,7 +578,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_042_011_SinglePropertyNa EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_042_012_OneToOne_conventions", "p08_BDD_EntityFramework\ex_042_012_OneToOne_conventions\ex_042_012_OneToOne_conventions.csproj", "{762C349D-5685-43FA-A077-2F3BDD07C898}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ex_042_013_OneToOne_FluentAPI", "p08_BDD_EntityFramework\ex_042_013_OneToOne_FluentAPI\ex_042_013_OneToOne_FluentAPI.csproj", "{ADF1001A-AF43-4D6E-9D4A-B0C26E4E19D5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ex_042_013_OneToOne_FluentAPI", "p08_BDD_EntityFramework\ex_042_013_OneToOne_FluentAPI\ex_042_013_OneToOne_FluentAPI.csproj", "{ADF1001A-AF43-4D6E-9D4A-B0C26E4E19D5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -3488,26 +3486,6 @@ Global {B506ECD8-853D-4E69-8F0A-AFCDB7FEABF3}.Release|x64.Build.0 = Release|Any CPU {B506ECD8-853D-4E69-8F0A-AFCDB7FEABF3}.Release|x86.ActiveCfg = Release|Any CPU {B506ECD8-853D-4E69-8F0A-AFCDB7FEABF3}.Release|x86.Build.0 = Release|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Debug|ARM.ActiveCfg = Debug|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Debug|ARM.Build.0 = Debug|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Debug|ARM64.Build.0 = Debug|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Debug|x64.ActiveCfg = Debug|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Debug|x64.Build.0 = Debug|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Debug|x86.ActiveCfg = Debug|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Debug|x86.Build.0 = Debug|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Release|Any CPU.Build.0 = Release|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Release|ARM.ActiveCfg = Release|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Release|ARM.Build.0 = Release|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Release|ARM64.ActiveCfg = Release|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Release|ARM64.Build.0 = Release|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Release|x64.ActiveCfg = Release|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Release|x64.Build.0 = Release|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Release|x86.ActiveCfg = Release|Any CPU - {4D079A62-B303-4900-BEC1-994BC26BCCA2}.Release|x86.Build.0 = Release|Any CPU {91FD20B6-250C-437B-9FBE-DA4D2B87DE03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {91FD20B6-250C-437B-9FBE-DA4D2B87DE03}.Debug|Any CPU.Build.0 = Debug|Any CPU {91FD20B6-250C-437B-9FBE-DA4D2B87DE03}.Debug|ARM.ActiveCfg = Debug|Any CPU @@ -4993,7 +4971,6 @@ Global {CF1AE501-3518-45CC-94AA-D6DE047EA022} = {13CDB6B1-9B1D-43A9-9E9E-08989D55ACA5} {26400B99-2FB6-4B5F-BE2B-D15124F2B51D} = {13CDB6B1-9B1D-43A9-9E9E-08989D55ACA5} {B506ECD8-853D-4E69-8F0A-AFCDB7FEABF3} = {3BD95300-E2F6-4CA6-B4CC-5D19DF5C6AC0} - {4D079A62-B303-4900-BEC1-994BC26BCCA2} = {593200F9-6D14-43BC-9289-8BB75FAC6552} {91FD20B6-250C-437B-9FBE-DA4D2B87DE03} = {593200F9-6D14-43BC-9289-8BB75FAC6552} {2C53F069-6E87-4A36-8915-E0219EBA8BA7} = {593200F9-6D14-43BC-9289-8BB75FAC6552} {C6EF99F3-959D-4096-8ABE-140596DD14BD} = {593200F9-6D14-43BC-9289-8BB75FAC6552} diff --git a/ex_042_007_EF_CF_One_to_One_FluentAPI/CarnetDeSante.cs b/ex_042_007_EF_CF_One_to_One_FluentAPI/CarnetDeSante.cs deleted file mode 100644 index 48fd11d..0000000 --- a/ex_042_007_EF_CF_One_to_One_FluentAPI/CarnetDeSante.cs +++ /dev/null @@ -1,42 +0,0 @@ -// ======================================================================== -// -// Copyright (C) 2016-2017 MARC CHEVALDONNE -// marc.chevaldonne.free.fr -// -// Module : CarnetDeSante.cs -// Author : Marc Chevaldonné -// Creation date : 2016-10-19 -// -// ======================================================================== - -using System; - -namespace ex_042_007_EF_CF_One_to_One_FluentAPI -{ - /// - /// CarnetDeSante est une classe POCO, i.e. Plain Old CLR Object - /// Elle a une relation 1-1 avec la classe Nounours via la propriété Owner. - /// - public class CarnetDeSante - { - public Guid UniqueId - { - get; set; - } - - public DateTime LastModified - { - get; set; - } - - public virtual Nounours Owner - { - get; set; - } - - public override string ToString() - { - return $"{UniqueId} : carnet de {Owner.Nom}, modifié la dernière fois le {LastModified.ToString("d")}"; - } - } -} diff --git a/ex_042_007_EF_CF_One_to_One_FluentAPI/DbContextInitializer.cs b/ex_042_007_EF_CF_One_to_One_FluentAPI/DbContextInitializer.cs deleted file mode 100644 index 017ad82..0000000 --- a/ex_042_007_EF_CF_One_to_One_FluentAPI/DbContextInitializer.cs +++ /dev/null @@ -1,79 +0,0 @@ -// ======================================================================== -// -// Copyright (C) 2016-2017 MARC CHEVALDONNE -// marc.chevaldonne.free.fr -// -// Module : DbContextInitializer.cs -// Author : Marc Chevaldonné -// Creation date : 2016-10-19 -// -// ======================================================================== - -using Microsoft.EntityFrameworkCore; -using System; - -namespace ex_042_007_EF_CF_One_to_One_FluentAPI -{ - /// - /// initialiseur de stratégies... - /// - public static class DbContextInitializer - { - /// - /// remplissage de la base avec des données stubbées. - /// - /// base à remplir - public static void Seed(NounoursDBEntities context) - { - SetInitializer(context, InitializationStrategies.DropCreateDatabaseAlways); - - 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 }; - - CarnetDeSante carnet1 = new CarnetDeSante { Owner = chewie, LastModified = DateTime.Today }; - CarnetDeSante carnet2 = new CarnetDeSante { Owner = yoda, LastModified = new DateTime(1980, 5, 21) }; - CarnetDeSante carnet3 = new CarnetDeSante { Owner = ewok, LastModified = new DateTime(1983, 5, 25) }; - - chewie.Carnet = carnet1; - yoda.Carnet = carnet2; - ewok.Carnet = carnet3; - - context.NounoursSet.AddRange(new Nounours[] { chewie, yoda, ewok }); - context.Carnets.AddRange(new CarnetDeSante[] { carnet1, carnet2, carnet3 }); - - context.SaveChanges(); - } - - /// - /// les différentes stratégies de création de la base - /// - public enum InitializationStrategies - { - CreateDatabaseIfNotExists, - DropCreateDatabaseIfModelChanges, - DropCreateDatabaseAlways - } - public static void SetInitializer(DbContext context, InitializationStrategies strategy) - { - switch(strategy) - { - //par défaut : crée la base seulement si elle n'existe pas - default: - case InitializationStrategies.CreateDatabaseIfNotExists: - context.Database.EnsureCreated(); - break; - - //recrée la base même si elle existe déjà - case InitializationStrategies.DropCreateDatabaseAlways: - context.Database.EnsureDeleted(); - context.Database.EnsureCreated(); - break; - - //recrée la base seulement si le modèle change : impossible aujourd'hui en Entity Framework Core... - case InitializationStrategies.DropCreateDatabaseIfModelChanges: - throw new NotImplementedException("Le mode DropCreateDatabaseIfModelChanges ne peut pas encore exister sous Entity Framework Core"); - } - } - } -} diff --git a/ex_042_007_EF_CF_One_to_One_FluentAPI/Nounours.cs b/ex_042_007_EF_CF_One_to_One_FluentAPI/Nounours.cs deleted file mode 100644 index ac86cef..0000000 --- a/ex_042_007_EF_CF_One_to_One_FluentAPI/Nounours.cs +++ /dev/null @@ -1,98 +0,0 @@ -// ======================================================================== -// -// Copyright (C) 2016-2017 MARC CHEVALDONNE -// marc.chevaldonne.free.fr -// -// Module : Nounours.cs -// Author : Marc Chevaldonné -// Creation date : 2016-10-19 -// -// ======================================================================== - -using System; - -namespace ex_042_007_EF_CF_One_to_One_FluentAPI -{ - /// - /// Nounours est une classe POCO, i.e. Plain Old CLR Object. - /// Elle a une relation 1-1 avec la classe CarnetDeSante via la propriété Carnet. - /// - public class Nounours - { - public Guid UniqueId - { - get; set; - } - - public virtual CarnetDeSante Carnet { get; set; } - - public string Nom - { - get; - set; - } - - public DateTime DateDeNaissance - { - get; - set; - } - - public int NbPoils - { - get; - set; - } - - /// - /// returns a hash code in order to use this class in hash table - /// - /// hash code - public override int GetHashCode() - { - return Nom.GetHashCode(); - } - - /// - /// checks if the "right" object is equal to this Nounours or not - /// - /// the other object to be compared with this Nounours - /// true if equals, false if not - public override bool Equals(object right) - { - //check null - if (object.ReferenceEquals(right, null)) - { - return false; - } - - if (object.ReferenceEquals(this, right)) - { - return true; - } - - if (this.GetType() != right.GetType()) - { - return false; - } - - return this.Equals(right as Nounours); - } - - /// - /// checks if this Nounours is equal to the other Nounours - /// - /// the other Nounours to be compared with - /// true if equals - public bool Equals(Nounours other) - { - return (this.Nom.Equals(other.Nom) && this.DateDeNaissance == other.DateDeNaissance); - } - - public override string ToString() - { - return $"{UniqueId}: {Nom} ({DateDeNaissance:dd/MM/yyyy}, {NbPoils} poils)"; - } - - } -} diff --git a/ex_042_007_EF_CF_One_to_One_FluentAPI/NounoursDBEntities.cs b/ex_042_007_EF_CF_One_to_One_FluentAPI/NounoursDBEntities.cs deleted file mode 100644 index a6c9759..0000000 --- a/ex_042_007_EF_CF_One_to_One_FluentAPI/NounoursDBEntities.cs +++ /dev/null @@ -1,66 +0,0 @@ -// ======================================================================== -// -// Copyright (C) 2016-2017 MARC CHEVALDONNE -// marc.chevaldonne.free.fr -// -// Module : NounoursDBEntities.cs -// Author : Marc Chevaldonné -// Creation date : 2016-10-19 -// -// ======================================================================== - -using Microsoft.EntityFrameworkCore; - -namespace ex_042_007_EF_CF_One_to_One_FluentAPI -{ - /// - /// La classe qui dérive de DbContext est celle qui permettra de faire les opérations CRUD sur le modèle. - /// Cette classe contient deux DbSet pour permettre de réaliser des opérations CRUD sur les types T, ici Nounours et CarnetDeSante. - /// - public class NounoursDBEntities : DbContext - { - public virtual DbSet NounoursSet { get; set; } - public virtual DbSet Carnets { get; set; } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ex_042_007_EF_CF_One_to_One_FluentAPI.Nounours.mdf;Trusted_Connection=True;"); - } - - /// - /// méthode appelée lors de la création du modèle. - /// - /// - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - //création de la table TableNounours - modelBuilder.Entity().ToTable("TableNounours"); //nom de la table - modelBuilder.Entity().HasKey(n => n.UniqueId); //définition de la clé primaire - modelBuilder.Entity().Property(n => n.UniqueId) - .ValueGeneratedOnAdd(); //définition du mode de génération de la clé : génération à l'insertion - modelBuilder.Entity().Property(n => n.Nom).IsRequired() - .HasMaxLength(256); //définition de la colonne Nom - modelBuilder.Entity().Property(n => n.DateDeNaissance).HasColumnName("Naissance"); //changement du nom de la colonne Naissance - //modelBuilder.Entity().Property(n => n.Carnet).IsRequired(); - //note : la colonne NbPoils n'est pas changée : utilisation des conventions EF - - //création de la table "Carnets" - modelBuilder.Entity().ToTable("Carnets"); // nom de la table - modelBuilder.Entity().HasKey(c => c.UniqueId); //définition de la clé primaire - //modelBuilder.Entity().Property(c => c.Owner).IsRequired(); - modelBuilder.Entity().Property(c => c.UniqueId) - .ValueGeneratedNever(); // définition du mode de génération de la clé : pas de génération automatique - //note : la colonne LastModified n'est pas touchée : utilisation des conventions EF - - - //on précise qu'il y a une relation entre CarnetDeSante et Nounours - modelBuilder.Entity() //l'entité Nounours... - .HasOne(n => n.Carnet) //a une propriété obligatoire Carnet... - .WithOne(c => c.Owner) //reliée à la propriété Owner du Carnet... - .HasForeignKey(c => c.UniqueId);//dont la propriété UniqueId est une Foreign Key - //remplace la ForeignKey - - base.OnModelCreating(modelBuilder); - } - } -} diff --git a/ex_042_007_EF_CF_One_to_One_FluentAPI/Program.cs b/ex_042_007_EF_CF_One_to_One_FluentAPI/Program.cs deleted file mode 100644 index 8fe6475..0000000 --- a/ex_042_007_EF_CF_One_to_One_FluentAPI/Program.cs +++ /dev/null @@ -1,75 +0,0 @@ -// ======================================================================== -// -// Copyright (C) 2016-2017 MARC CHEVALDONNE -// marc.chevaldonne.free.fr -// -// Module : Program.cs -// Author : Marc Chevaldonné -// Creation date : 2016-10-18 -// -// ======================================================================== - -using System; -using static System.Console; - -namespace ex_042_007_EF_CF_One_to_One_FluentAPI -{ - public class Program - { - /// - /// Cet exemple montre comment construire une relation 1-1 dans la base de données en utilisant la Fluent API. - /// On préférera cette solution par exemple lorsque nous n'avons pas accès à la classe Model et que nous ne pouvons donc pas utiliser les conventions de nommage - /// comme dans l'exemple précédent. - /// - /// on utilise les données stubbées de MyStubDataInitializationStrategy - /// On affiche les Nounours et les Carnets de santé. - /// Constatez que les identifiants sont bien les mêmes à cause de la relation 1-1. - /// - static void Main(string[] args) - { - OutputEncoding = System.Text.Encoding.UTF8; - - try - { - using (NounoursDBEntities db = new NounoursDBEntities()) - { - //choix de la stratégie et remplissage avec des données stubbées - DbContextInitializer.Seed(db); - - WriteLine("nounours : "); - foreach (var n in db.NounoursSet) - { - WriteLine($"\t{n}, LastModified: {n.Carnet.LastModified.ToString("d")}"); - } - - WriteLine("carnets de santé : "); - foreach (var c in db.Carnets) - { - WriteLine($"\t{c}"); - } - - } - } - catch (NotImplementedException exception) - { - WriteLine(exception.Message); - } - catch (Exception e) - { - 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 suivantes (que vous retrouvez en commentaires dans la classe Program) :"); - WriteLine("Pour créer la base, ouvrez un invite de commandes et placez-vous dans le dossier de ce projet, ou bien,"); - WriteLine("- dans Visual Studio ouvrez la Console du Gestionnaire de package (Outils -> Gestionnaire de package NuGet -> Console du Gestionnaire de package),"); - WriteLine("- dans cette Console, vous devriez être dans le dossier de la solution, déplacez-vous dans celui du projet (ici : cd ex_042_007_EF_CF_One_to_One_FluentAPI)"); - WriteLine("- tapez : dotnet restore (pour restaurer les packages .NET Core)"); - WriteLine("- tapez : dotnet ef migrations add MyFirstMigration"); - WriteLine(" note : vous pourrez détruire le dossier Migrations une fois la base créée"); - WriteLine("- tapez : dotnet ef database update"); - WriteLine(" Ceci génère la base de données en utilisant la migration, et en particulier votre classe DBContext et vos classes POCO."); - WriteLine("\nDans cet exemple, une base de données SQLServer est créée et en particulier la table Nounours.mdf"); - } - - ReadLine(); - } - } -} diff --git a/ex_042_007_EF_CF_One_to_One_FluentAPI/ex_042_007_EF_CF_One_to_One_FluentAPI.csproj b/ex_042_007_EF_CF_One_to_One_FluentAPI/ex_042_007_EF_CF_One_to_One_FluentAPI.csproj deleted file mode 100644 index 48bd9bc..0000000 --- a/ex_042_007_EF_CF_One_to_One_FluentAPI/ex_042_007_EF_CF_One_to_One_FluentAPI.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - netcoreapp3.0 - ex_042_007_EF_CF_One_to_One_FluentAPI - Exe - ex_042_007_EF_CF_One_to_One_FluentAPI - 3.0.1 - false - false - false - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - diff --git a/p08_BDD_EntityFramework/ReadMe.md b/p08_BDD_EntityFramework/ReadMe.md index 759eae3..beee7c3 100644 --- a/p08_BDD_EntityFramework/ReadMe.md +++ b/p08_BDD_EntityFramework/ReadMe.md @@ -32,9 +32,10 @@ Ce chapitre s'attardera sur le lien entre le mod * [**ex_042_008 : Data Seeding before Entity Framework 2.1**](ex_042_008_DataSeeding_before_EF2.1) : explique comment utiliser un stub (méthode qui était recommandée avant EF Core 2.1) * [**ex_042_009 : Data Seeding**](ex_042_009_DataSeeding) : explique comment utiliser un stub (méthode recommandée depuis EF Core 2.1) * [**Relationships**](Relationships.md) : en cliquant [ici](Relationships.md), vous aurez plus de détails sur les relations entre entités - * [**ex_042_010 : Single Property navigation with data annotations**](ex_042_010_SinglePropertyNavigation_conventions) : montre comment une relation d'association est traduite par **EF Core** lorsque cette association est unidirectionnelle entre deux entités, en utilisant les conventions d'écriture et/ou les annotations de données. - * [**ex_042_011 : Single Property navigation with Fluent API**](ex_042_011_SinglePropertyNavigation_FluentAPI) : montre comment une relation d'association est traduite par **EF Core** lorsque cette association est unidirectionnelle entre deux entités, en utilisant la *FLuent API*. - * [**ex_042_012 : One To One with data annotations**](ex_042_012_OneToOne_conventions) : montre comment une relation d'association *One To One* est traduite par **EF Core** lorsque cette association est bidirectionnelle entre deux entités, en utilisant l'*annotation de données*. + * [**ex_042_010 : Single Property navigation with data annotations**](ex_042_010_SinglePropertyNavigation_conventions) : montre comment une relation d'association est traduite par *EF Core* lorsque cette association est unidirectionnelle entre deux entités, en utilisant les conventions d'écriture et/ou les annotations de données. + * [**ex_042_011 : Single Property navigation with Fluent API**](ex_042_011_SinglePropertyNavigation_FluentAPI) : montre comment une relation d'association est traduite par *EF Core* lorsque cette association est unidirectionnelle entre deux entités, en utilisant la *FLuent API*. + * [**ex_042_012 : One To One with data annotations**](ex_042_012_OneToOne_conventions) : montre comment une relation d'association *One To One* est traduite par *EF Core* lorsque cette association est bidirectionnelle entre deux entités, en utilisant l'*annotation de données*. + * [**ex_042_013 : One To One with Fluent API**](ex_042_013_OneToOne_FluentAPI) : montre comment une relation d'association *One To One* est traduite par *EF Core* lorsque cette association est bidirectionnelle entre deux entités, en utilisant la *FluentAPI*. 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. 4. *Querying (LINQ to SQL) and saving data* : diff --git a/p08_BDD_EntityFramework/ex_042_013_OneToOne_FluentAPI/NounoursDBEntities.cs b/p08_BDD_EntityFramework/ex_042_013_OneToOne_FluentAPI/NounoursDBEntities.cs index 6adbb1e..1595609 100644 --- a/p08_BDD_EntityFramework/ex_042_013_OneToOne_FluentAPI/NounoursDBEntities.cs +++ b/p08_BDD_EntityFramework/ex_042_013_OneToOne_FluentAPI/NounoursDBEntities.cs @@ -34,7 +34,6 @@ namespace ex_042_013_OneToOne_FluentAPI //création de la table "Carnets" modelBuilder.Entity().ToTable("Carnets"); // nom de la table modelBuilder.Entity().HasKey(c => c.UniqueId); //définition de la clé primaire - //modelBuilder.Entity().Property(c => c.Owner).IsRequired(); modelBuilder.Entity().Property(c => c.UniqueId) .ValueGeneratedNever(); // définition du mode de génération de la clé : pas de génération automatique //note : la colonne LastModified n'est pas touchée : utilisation des conventions EF diff --git a/p08_BDD_EntityFramework/ex_042_013_OneToOne_FluentAPI/Program.cs b/p08_BDD_EntityFramework/ex_042_013_OneToOne_FluentAPI/Program.cs index 616b186..e0c3a26 100644 --- a/p08_BDD_EntityFramework/ex_042_013_OneToOne_FluentAPI/Program.cs +++ b/p08_BDD_EntityFramework/ex_042_013_OneToOne_FluentAPI/Program.cs @@ -8,7 +8,7 @@ namespace ex_042_013_OneToOne_FluentAPI public class Program { /// - /// Cet exemple montre comment construire une relation 1-1 dans la base de données en utilisant les conventions de nommage Entity Framework. + /// Cet exemple montre comment construire une relation 1-1 dans la base de données en utilisant la Fluent API d'Entity Framework. /// static void Main(string[] args) { diff --git a/p08_BDD_EntityFramework/ex_042_013_OneToOne_FluentAPI/ReadMe.md b/p08_BDD_EntityFramework/ex_042_013_OneToOne_FluentAPI/ReadMe.md index ebd8918..b0bbfc4 100644 --- a/p08_BDD_EntityFramework/ex_042_013_OneToOne_FluentAPI/ReadMe.md +++ b/p08_BDD_EntityFramework/ex_042_013_OneToOne_FluentAPI/ReadMe.md @@ -1,12 +1,12 @@ -# ex_042_012_OneToOne_conventions +# ex_042_013_OneToOne_FluentAPI *20/01/2020 ⋅ Marc Chevaldonné* --- -Cet exemple montre comment réaliser une relation *One To One* entre deux entités avec *Entity Framework Core* et l'*annotation de données*. -Une version équivalente réalisée avec la *Fluent API* est disponible dans l'exemple -[**ex_042_013 : One To One with Fluent API**](../ex_042_013_OneToOne_FluentAPI) +Cet exemple montre comment réaliser une relation *One To One* entre deux entités avec *Entity Framework Core* et la *Fluent API*. +Une version équivalente réalisée avec les *annotations de données* est disponible dans l'exemple +[**ex_042_012 : One To One with data annotations**](../ex_042_012_OneToOne_conventions) --- @@ -23,7 +23,7 @@ Une version équivalente réalisée avec la *Fluent API* est disponible dans l'e Un ```Nounours``` contient différentes propriétés (```Nom```, ```DateDeNaissance```, ```NbPoils```) dont ```Carnet``` de type ```CarnetDeSante```. Un ```CarnetDeSante``` possède une propriété de type ```DateTime``` (```LastModified```), et une propriété ```Owner``` de type ```Nounours```. On a donc bien une relation *One To One* puisqu'un ```Nounours``` possède un ```CarnetDeSante``` et qu'un ```CarnetDeSante``` possède un ```Nounours```. - + Ce qu'il faut noter : * ```Nounours``` possède une association vers ```CarnetDeSante``` @@ -34,18 +34,8 @@ public CarnetDeSante Carnet { get; set; } ```csharp public Nounours Owner { get; set; } ``` -* ```Nounours``` possède un identifiant unique (qui peut être utilisé par convention d'écriture ou _annotation de données_) : ```[Key]```. -* Cet identifiant est généré par la base : ```[DatabaseGenerated(DatabaseGeneratedOption.Identity)]```. -* ```CarnetDeSante``` possède un identifiant unique (qui peut être utilisé par convention d'écriture ou _annotation de données_) : ```[Key]```. -* Cet identifiant fait référence à une clé étrangère qui est la clé primaire associée à l'entité pointée par sa propriété ```Owner``` : ```ForeignKey("Owner")```. -```csharp -[Key, ForeignKey("Owner")] -public int UniqueId -{ - get; set; -} -``` -* En conséquence, l'identifiant unique ```UniqueId``` de ```CarnetDeSante``` aura la même valeur que l'```UniqueId``` d'une entité ```Nounours```. +* ```Nounours``` possède un identifiant unique ```UniqueId```. +* ```CarnetDeSante``` possède un identifiant unique ```UniqueId```. ### La classe ```NounoursDBEntities``` @@ -56,9 +46,80 @@ public int UniqueId public DbSet NounoursSet { get; set; } public DbSet Carnets { get; set; } ``` -##### Quelques explications supplémentaires : +* La classe réécrit ensuite la méthode ```OnModelCreating``` : +```csharp +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + //création de la table TableNounours + modelBuilder.Entity().ToTable("TableNounours"); //nom de la table + modelBuilder.Entity().HasKey(n => n.UniqueId); //définition de la clé primaire + modelBuilder.Entity().Property(n => n.UniqueId) + .ValueGeneratedOnAdd(); //définition du mode de génération de la clé : génération à l'insertion + modelBuilder.Entity().Property(n => n.Nom).IsRequired() + .HasMaxLength(256); //définition de la colonne Nom + modelBuilder.Entity().Property(n => n.DateDeNaissance).HasColumnName("Naissance").HasColumnType("date"); //changement du nom de la colonne Naissance + + //création de la table "Carnets" + modelBuilder.Entity().ToTable("Carnets"); // nom de la table + modelBuilder.Entity().HasKey(c => c.UniqueId); //définition de la clé primaire + modelBuilder.Entity().Property(c => c.UniqueId) + .ValueGeneratedNever(); // définition du mode de génération de la clé : pas de génération automatique + //note : la colonne LastModified n'est pas touchée : utilisation des conventions EF + + + //on précise qu'il y a une relation entre CarnetDeSante et Nounours + modelBuilder.Entity() //l'entité Nounours... + .HasOne(n => n.Carnet) //a une propriété obligatoire Carnet... + .WithOne(c => c.Owner) //reliée à la propriété Owner du Carnet... + .HasForeignKey(c => c.UniqueId);//dont la propriété UniqueId est une Foreign Key + //remplace la ForeignKey + + base.OnModelCreating(modelBuilder); +} +``` +Voyons cette méthode plus en détails. +Tout d'abord, il y a la définition des détails de la table de ```Nounours``` : +* le changement de nom de la table : +```csharp +modelBuilder.Entity().ToTable("TableNounours"); +``` +* la définition de la clé primaire : +```csharp +modelBuilder.Entity().HasKey(n => n.UniqueId); +modelBuilder.Entity().Property(n => n.UniqueId) + .ValueGeneratedOnAdd(); +``` +* définition de contraintes sur les colonnes de ```Nounours``` : +```csharp +modelBuilder.Entity().Property(n => n.Nom) + .IsRequired() + .HasMaxLength(256); +modelBuilder.Entity().Property(n => n.DateDeNaissance) + .HasColumnName("Naissance") + .HasColumnType("date"); +``` +On continue avec la définition des détails de la table de ```CarnetDeSante``` : +* le changement de nom de la table : +```csharp +modelBuilder.Entity().ToTable("Carnets"); +``` +* la définition de la clé primaire (*notez qu'on ne demande pas ici à la base de générer la clé, puisqu'on va utiliser une clé étrangère*) : +```csharp +modelBuilder.Entity().HasKey(c => c.UniqueId); +modelBuilder.Entity().Property(c => c.UniqueId) + .ValueGeneratedNever(); +``` +On s'intéresse enfin à la **relation _One To One_**, où l'on précise qu'une entité ```Nounours``` possède une association vers l'entité de type ```CarnetDeSante``` grâce à la propriété ```Carnet``` (```.HasOne(n => n.Carnet)```). +Cette entité ```CarnetDeSante``` possède elle-même une association vers une entité de type ```Nounours``` grâce à sa propriété ```Owner``` (```.WithOne(c => c.Owner)```), +et on précise que cette entité ```CarnetDeSante``` voit sa propriété ```UniqueId``` utilisée comme clé étrangère (```.HasForeignKey(c => c.UniqueId)```). Elle automatiquement reliée à la clé primaire de ```Nounours```. +```csharp +modelBuilder.Entity() //l'entité Nounours... + .HasOne(n => n.Carnet) //a une propriété obligatoire Carnet... + .WithOne(c => c.Owner) //reliée à la propriété Owner du Carnet... + .HasForeignKey(c => c.UniqueId);//dont la propriété UniqueId est une Foreign Key +``` Pour pouvoir relier une entité ```Nounours``` à une entité ```CarnetDeSante``` de manière bidirectionnelle, les propriétés ```Nounours.Carnet``` et ```CarnetDeSante.Owner``` sont suffisantes, à condition qu'une clé étrangère soit déclarée et utilisée. -C'est le cas grâce à l'annotation de données ```ForeignKey("Owner")``` qui s'occupe de définir de quelle manière les deux entités sont reliées. +C'est le cas grâce au code précédent qui s'occupe de définir de quelle manière les deux entités sont reliées. ### La classe ```StubbedContext``` @@ -147,7 +208,7 @@ Pour tester cette application, n'oubliez pas les commandes comme présentées da * Ouvrez la *Console du Gestionnaire de package* sous Windows ou le *Terminal* sous MacOSX, 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_012_OneToOne_conventions +cd .\p08_BDD_EntityFramework\ex_042_013_OneToOne_FluentAPI ``` *Note*: si vous n'avez pas installé correctement EntityFrameworkCore, il vous faudra peut-être utiliser également : @@ -159,14 +220,14 @@ cd .\p08_BDD_EntityFramework\ex_042_012_OneToOne_conventions * Migration : ``` -dotnet ef migrations add ex_042_012 --context StubbedContext +dotnet ef migrations add ex_042_013 --context StubbedContext ``` * Création de la table : ``` dotnet ef database update --context StubbedContext ``` * Génération et exécution -Vous pouvez maintenant générer et exécuter l'exemple **ex_042_012_OneToOne_conventions**. +Vous pouvez maintenant générer et exécuter l'exemple **ex_042_013_OneToOne_FluentAPI**. * Le résultat de l'exécution va ressembler à : ``` @@ -197,7 +258,7 @@ Contenu de la base (carnets de santé) : ## Comment exécuter cet exemple sans le stub ? Il suffit de faire exactement comme dans le paragraphe précédent, mais en choisissant le contexte ```NounoursDBEntities``` à la place de ```StubbedContext``` : ``` -dotnet ef migrations add ex_042_012 --context NounoursDBEntities +dotnet ef migrations add ex_042_013 --context NounoursDBEntities dotnet ef database update --context NounoursDBEntities ``` Lors de l'exécution, le résultat sera évidemment différent puisqu'il n'y aura pas les 3 nounours du stub. @@ -206,11 +267,11 @@ Lors de l'exécution, le résultat sera évidemment différent puisqu'il n'y aur Pour vérifier le contenu de votre base SQLite, vous pouvez utiliser le programme *DB Browser* : * Rendez-vous sur la page : https://sqlitebrowser.org/dl/ et téléchargez le programme *DB Browser*. * Lancez *DB Browser for SQLite* -* Glissez-déposez au milieu de la fenêtre de *DB Browser for SQLite* le fichier *ex_042_012_OneToOne_conventions.Nounours.db* qui a été généré par l'exécution du programme et qui se trouve près de *ex_042_012_OneToOne_conventions.csproj*. -![DB Browser for SQLite](./readme_files/dbbrowser01.png) +* Glissez-déposez au milieu de la fenêtre de *DB Browser for SQLite* le fichier *ex_042_013_OneToOne_FluentAPI.Nounours.db* qui a été généré par l'exécution du programme et qui se trouve près de *ex_042_012_OneToOne_conventions.csproj*. +![DB Browser for SQLite](../ex_042_012_OneToOne_conventions/readme_files/dbbrowser01.png) * Choisissez ensuite l'onglet *Parcourir les données* * Observez les résultats obtenus des deux tables -![DB Browser for SQLite](./readme_files/dbbrowser02.png) -![DB Browser for SQLite](./readme_files/dbbrowser03.png) +![DB Browser for SQLite](../ex_042_012_OneToOne_conventions/readme_files/dbbrowser02.png) +![DB Browser for SQLite](../ex_042_012_OneToOne_conventions/readme_files/dbbrowser03.png) diff --git a/p08_BDD_EntityFramework/temp.md b/p08_BDD_EntityFramework/temp.md index e6506a1..00f381f 100644 --- a/p08_BDD_EntityFramework/temp.md +++ b/p08_BDD_EntityFramework/temp.md @@ -19,7 +19,7 @@ * V 010, 011 shadow properties * V 010, 011, single navigation property * cascade delete - * 012 one to one + * V 012 013 one to one * one to many * many to many * dictionaries