You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mchsamples-.net-core/p08_BDD_EntityFramework/ex_042_011_SinglePropertyNa...
Marc CHEVALDONNE a773557095
continuous-integration/drone/push Build is failing Details
update to .NET6
2 years ago
..
Information.cs added ex_042_011 5 years ago
Nounours.cs added ex_042_011 5 years ago
NounoursDBEntities.cs minor fixes and read me 5 years ago
NounoursDBEntitiesWithStub.cs added ex_042_011 5 years ago
Program.cs added ex_042_011 5 years ago
ReadMe.md minor fixes and read me 5 years ago
ex_042_011_SinglePropertyNavigation_FluentAPI.csproj update to .NET6 2 years ago

ReadMe.md

ex_042_011_SinglePropertyNavigation_FluentAPI

19/01/2020 ⋅ Marc Chevaldonné


Cet exemple montre comment réaliser une navigation entre deux entités avec une propriété simple (sens unique) avec Entity Framework Core et la Fluent API.
Une version équivalente réalisée avec la Fluent API est disponible dans l'exemple ex_042_010 : Single Property navigation with data annotations


Comment est construit cet exemple ?

  • Le projet est de type .NET Core
  • Il contient quatre classes :
    • Nounours
    • Information
    • NounoursDBEntities
    • NounoursDBEntitiesWithStub

Les classes entités : Nounours et Information

Un Nounours contient différentes propriétés (Nom, DateDeNaissance, NbPoils) dont Information de type Information.
Une Information possède deux propriétés de type string, mais aucun lien vers Nounours.

Ce qu'il faut noter :

  • Nounours possède un identifiant unique (qui peut être utilisé par convention d'écriture ou data annotation).
  • Information possède un identifiant unique (qui peut être utilisé par convention d'écriture ou data annotation).
  • Nounours possède une association vers Information
public Information Information
{
    get; set;
}
  • Information NE possède PAS d'association vers Nounours

La classe NounoursDBEntities

  • Comme dans les exemples précédents, NounoursDBEntities dérive de DbContext.
  • NounoursDBEntities déclare un seul DbSet de Nounours.
public DbSet<Nounours> NounoursSet { get; set; }
  • Dans cet exemple, NounoursDBEntities NE déclare PAS de DbSetd'Information (toutefois, l'exemple fonctionerait de la même manière si c'était le cas).
  • La méthode OnModelCreating est réécrite et écrasera donc une partie des conventions d'écriture ou des annotations de données. Ici, par exemple, elle donne quelques indications sur la classe Nounours comme nous l'avons déjà vu dans les exemples précédents :
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Nounours>().HasKey(n => n.UniqueId);
    modelBuilder.Entity<Nounours>().Property(n => n.UniqueId).ValueGeneratedOnAdd();

    modelBuilder.Entity<Nounours>().Property(n => n.DateDeNaissance).HasColumnName("Naissance").HasColumnType("date");

    //...

    base.OnModelCreating(modelBuilder);
}
  • Puis, ce qui nous intéresse plus particulièrement ici, elle définit la relation entre Nounours et Information : une entité Nounours possède une entité Information sans navigation inverse.
modelBuilder.Entity<Nounours>().HasOne(n => n.Information);
Quelques explications supplémentaires :
  • Même si NounoursDBEntities ne déclare pas de DbSetd'Information, EntityFramework Core détecte qu'il va falloir créer une table d'Information lors de la migration. Nous pourrons nous en apercevoir plus tard dans ce document lorsque nous regarderons le résultat de la table.
  • Pour pouvoir relier une entité Nounours à une entité Information, la propriété Information n'est pas suffisante. Il faut également une propriété dans la classe Nounours du type de l'identifiant de la classe Information pour faire le lien. Mais EntityFramework Core se charge de sa création lors de la migration. (Vous pouvez l'ajouter vous-même si vous préférez) Elle est l'équivalent de : public int InformationId {get; set;} mais n'a pas été écrite par le développeur : on parle alors de shadow property.

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.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    var info1 = new Information { InformationId = 1, MadeBy = "George Lucas", MadeIn = "Kashyyyk" };
    var info2 = new Information { InformationId = 2, MadeBy = "George Lucas", MadeIn = "Dagobah" };
    var info3 = new Information { InformationId = 3, MadeBy = "George Lucas", MadeIn = "Lune forestière d'Endor" };

    modelBuilder.Entity<Information>().HasData(info1, info2, info3);

    modelBuilder.Entity<Nounours>().Property<int>("InformationId");

    modelBuilder.Entity<Nounours>().HasData(
        new { UniqueId = Guid.Parse("{4422C524-B2CB-43EF-8263-990C3CEA7CAE}"), Nom = "Chewbacca", DateDeNaissance = new DateTime(1977, 5, 27), NbPoils = 1234567, InformationId = 1 },
        new { UniqueId = Guid.Parse("{A4F84D92-C20F-4F2D-B3F9-CA00EF556E72}"), Nom = "Yoda", DateDeNaissance = new DateTime(1980, 5, 21), NbPoils = 3, InformationId = 2 },
        new { UniqueId = Guid.Parse("{AE5FE535-F041-445E-B570-28B75BC78CB9}"), Nom = "Ewok", DateDeNaissance = new DateTime(1983, 5, 25), NbPoils = 3456789, InformationId = 3 }
        );
}

Elle crée d'abord des entités d'Information

var info1 = new Information { InformationId = 1, MadeBy = "George Lucas", MadeIn = "Kashyyyk" };
var info2 = new Information { InformationId = 2, MadeBy = "George Lucas", MadeIn = "Dagobah" };
var info3 = new Information { InformationId = 3, MadeBy = "George Lucas", MadeIn = "Lune forestière d'Endor" };

et les ajoute à la base :

modelBuilder.Entity<Information>().HasData(info1, info2, info3);

Elle va ensuite créer des instances de Nounours et les ajouter à la base, mais pour cela, il lui faut donner l'identifiant de l'Information à lier au Nounours. Nous sommes donc obligés dans ce cas de fournir la propriété InformationId dans Nounours pour pouvoir les lier. Deux solutions existent alors :

  1. soit vous rajoutez une propriété InformationId dans Nounours : mais c'est dommage d'avoir à le faire uniquement pour un stub.
  2. soit vous rajoutez la shadow property directement dans cette méthode OnModelCreating avec la ligne suivante qui est alors équivalente et permet de rajouter une propriété à une entité :
modelBuilder.Entity<Nounours>().Property<int>("InformationId");

On peut ensuite créer les instances de Nounours et les relier aux instances de Information en utilisant la nouvelle propriété InformationId de Nounours correspondant à la clé primaire de Information.

modelBuilder.Entity<Nounours>().HasData(
    new { UniqueId = Guid.Parse("{4422C524-B2CB-43EF-8263-990C3CEA7CAE}"), Nom = "Chewbacca", DateDeNaissance = new DateTime(1977, 5, 27), NbPoils = 1234567, InformationId = 1 },
    new { UniqueId = Guid.Parse("{A4F84D92-C20F-4F2D-B3F9-CA00EF556E72}"), Nom = "Yoda", DateDeNaissance = new DateTime(1980, 5, 21), NbPoils = 3, InformationId = 2 },
    new { UniqueId = Guid.Parse("{AE5FE535-F041-445E-B570-28B75BC78CB9}"), Nom = "Ewok", DateDeNaissance = new DateTime(1983, 5, 25), NbPoils = 3456789, InformationId = 3 }
    );

La classe Program

  • NounoursDBEntitiesWithStub est ensuite utilisée dans Program pour remplir la base de manière tout à fait classique et ne nécessite aucun appel supplémentaire.
using (NounoursDBEntities db = new NounoursDBEntities())
{
    WriteLine("Contenu de la base :");
    foreach (var n in db.NounoursSet.Include(n => n.Information))
    {
        WriteLine($"\t{n}");
    }

}

Toutefois, si on ne précise pas qu'on veut également récupérer les contenus des propriétés Information des Nounours, EF Core ne le fera et ne chargera que les propriétés simples des Nounours. Pour forcer EF Core à charger également les données d'Information, on utilise la méthode d'extension Include :

db.NounoursSet.Include(n => n.Information)

db.NounoursSet récupère les données de la table de Nounours et .Include(n => n.Information) permet de préciser qu'on veut également récupérer les entités d'Information associées à ces Nounours.

  • La suite de l'exemple ajoute un nouveau Nounours et affiche le contenu de la base de données.
db.NounoursSet.Add(new Nounours { Nom = "Porg", DateDeNaissance = new DateTime(2017, 07, 19), NbPoils = 123, Information = new Information { MadeIn = "Ahch-To", MadeBy = "Jake Lunt Davies" } });
db.SaveChangesAsync();
using (NounoursDBEntities db = new NounoursDBEntities())
{
    WriteLine("Contenu de la base :");
    foreach (var n in db.NounoursSet.Include(n => n.Information))
    {
        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_011_SinglePropertyNavigation_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_011 --context NounoursDBEntitiesWithStub
  • Création de la table :
dotnet ef database update --context NounoursDBEntitiesWithStub
  • Génération et exécution Vous pouvez maintenant générer et exécuter l'exemple ex_042_011_SinglePropertyNavigation_FluentAPI.

  • Le résultat de l'exécution va ressembler à :

Contenu de la base :
      4422c524-b2cb-43ef-8263-990c3cea7cae: Chewbacca (27/05/1977, 1234567 poils, fait à Kashyyyk par George Lucas)
      a4f84d92-c20f-4f2d-b3f9-ca00ef556e72: Yoda (21/05/1980, 3 poils, fait à Dagobah par George Lucas)
      ae5fe535-f041-445e-b570-28b75bc78cb9: Ewok (25/05/1983, 3456789 poils, fait à Lune forestière d'Endor par George Lucas)

Ajout d'un nouveau nounours...

Contenu de la base :
      4422c524-b2cb-43ef-8263-990c3cea7cae: Chewbacca (27/05/1977, 1234567 poils, fait à Kashyyyk par George Lucas)
      a4f84d92-c20f-4f2d-b3f9-ca00ef556e72: Yoda (21/05/1980, 3 poils, fait à Dagobah par George Lucas)
      ae5fe535-f041-445e-b570-28b75bc78cb9: Ewok (25/05/1983, 3456789 poils, fait à Lune forestière d'Endor par George Lucas)
      dc53d93d-e15a-458d-94c9-bb3a61063377: Porg (19/07/2017, 123 poils, fait à Ahch-To par Jake Lunt Davies)

Note : l'identifiant du dernier Nounours sera vraisemblablement différent puisqu'il est créé par la base lors de l'insertion.

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

dotnet ef migrations add migration_ex_042_010 --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.

Comment vérifier quelles base et tables ont été créées et leur contenu ?

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_011_SinglePropertyNavigation_FluentAPI.Nounours.db qui a été généré par l'exécution du programme et qui se trouve près de ex_042_011_SinglePropertyNavigation_FluentAPI.csproj. DB Browser for SQLite
  • Vous pouvez remarquer que, même si NounoursDBEntites ne déclare pas de DbSet<Information>, une table d'Information a bien été créée.
  • Choisissez ensuite l'onglet Parcourir les données
  • Observez les résultats obtenus des deux tables DB Browser for SQLite DB Browser for SQLite