continuous-integration/drone/push Build is failing
Details
|
2 years ago | |
---|---|---|
.. | ||
readme_files | 5 years ago | |
Album.cs | 5 years ago | |
AlbumDBEntities.cs | 5 years ago | |
Morceau.cs | 5 years ago | |
Program.cs | 5 years ago | |
ReadMe.md | 5 years ago | |
StubbedContext.cs | 5 years ago | |
ex_042_015_OneToMany_conventions.csproj | 2 years ago |
ReadMe.md
ex_042_015_OneToMany_conventions
22/01/2020 ⋅ Marc Chevaldonné
Cet exemple montre comment réaliser une relation One To Many entre deux entités
avec Entity Framework Core et les conventions d'écriture avec génération
implicite d'une clé étrangère.
Une version équivalente réalisée avec les annotations de données et
l'établissement d'une clé étrangère de manière explicite est disponible dans
l'exemple
ex_042_014 : One To Many with data annotations
Une version équivalente réalisée avec la Fluent API est disponible dans l'exemple
ex_042_016 : One To Many with Fluent API
Comment est construit cet exemple ?
- Le projet est de type .NET Core
- Il contient quatre classes :
Album
Morceau
AlbumDBEntities
StubbedContext
Les classes entités : Album
et Morceau
La relation One To Many est mise en évidence de la manière suivante :
un Album
possède plusieurs Morceau
, et un Morceau
possède
un Album
.
Un Album
contient différentes propriétés (Titre
, DateDeSortie
)
dont Morceaux
de type ICollection<Morceau>
.
Un Morceau
possède une propriété de type string
(Titre
), et
une propriété Album
de type Album
.
Ce qu'il faut noter :
Album
possède une association versMorceau
public ICollection<Morceau> Morceaux { get; set; } = new List<Morceau>();
Morceau
possède une association versAlbum
public Album Album { get; set; }
Album
possède un identifiant uniqueAlbumId
(qui par convention d'écriture, sera la clé primaire et sera généré par la base lors de l'insertion).Morceau
possède un identifiant uniqueMorceauId
(qui par convention d'écriture, sera la clé primaire et sera généré par la base lors de l'insertion).- Le lien entre les deux tables va se faire avec l'ajout d'une colonne dans la table
de
Morceau
qui permettra de stocker l'Album
auquel ceMorceau
est lié. Dans le cas de l'utilisation des conventions d'écriture, ceci peut se faire explicitement ou implicitement. Cet exemple, le fait de manière implicite avec les conventions d'écriture. Mais il est possible de le faire de manière explicite en utilisant les annotations de données (cf. ex_042_014 : One To Many with data annotations) ou de manière explicite en utilisant la Fluent API (cf. ex_042_016 : One To Many with Fluent API). Toutefois, pour l'utilisation de données stubbées, il est nécessaire d'expliciter cette propriété (cf. plus bas, lors de l'utilisation deStubbedContext
). Ici, on __N'__ajoute PAS de nouvelle propriété àMorceau
pour stocker l'identifiant unique deAlbum
comme dans l'exemple ex_042_014 : One To Many with data annotations.
La classe AlbumDBEntities
- Comme dans les exemples précédents,
AlbumDBEntities
dérive deDbContext
. AlbumDBEntities
déclare deuxDbSet
: un deAlbum
et l'autre deMorceau
.
public DbSet<Album> Albums { get; set; }
public DbSet<Morceau> Morceaux { get; set; }
Quelques explications supplémentaires :
Comme dit plus haut, le lien entre les deux tables va se faire avec l'ajout d'une
colonne dans la table de Morceau
qui permettra de stocker l'Album
auquel ce Morceau
est lié.
Dans le cas de l'utilisation des conventions d'écriture et des
annotations de données, ceci peut se faire explicitement ou implicitement.
Cet exemple, le fait de manière implicite avec les conventions d'écriture. Mais il
est possible de le faire de manière explicite en utilisant les annotations de données
(cf. ex_042_014 : One To Many with dataAnnotations)
ou de manière explicite en utilisant la Fluent API (cf. ex_042_016 : One To Many with Fluent API).
Ici, c'est EF Core qui ajoute automatiquement une propriété AlbumId
à Morceau
: c'est la clé étrangère. Le nom de cette propriété est choisi à
partir d'une combinaison du nom de la propriété allant de Morceau
à Album
(ici Album
),
du type pointé par la clé étrangère (ici Album
), et de Id
=> ici EF Core
a choisi AlbumId
.
Tout ceci est fait automatiquement.
Toutefois, pour l'utilisation de données stubbées, il est nécessaire d'expliciter
cette propriété (cf. plus bas, lors de l'utilisation de StubbedContext
).
La classe StubbedContext
StubbedContext
est une classe fille deAlbumDBEntities
. 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éthodeOnModelCreating
qui appelle la méthode de la classe mère puis ajoute des instances d'entités, grâce à la méthode d'extensionHasData
.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
Album kindofblue = new Album { AlbumId=1, Titre = "Kind of Blue", DateDeSortie = new DateTime(1959, 8, 17) };
Album dialogue = new Album { AlbumId=2, Titre = "Dialogue", DateDeSortie = new DateTime(1965, 9, 1) };
modelBuilder.Entity<Album>().HasData(kindofblue, dialogue);
modelBuilder.Entity<Morceau>().Property<int>("AlbumId");
modelBuilder.Entity<Morceau>().HasData(new { MorceauId = 1, AlbumId = 1, Titre = "So What" },
new { MorceauId = 2, AlbumId = 1, Titre = "Freddie Freeloader" },
new { MorceauId = 3, AlbumId = 1, Titre = "Blue in Green" },
new { MorceauId = 4, AlbumId = 1, Titre = "All Blues" },
new { MorceauId = 5, AlbumId = 1, Titre = "Flamenco Sketches" },
new { MorceauId = 6, AlbumId = 2, Titre = "Catta" },
new { MorceauId = 7, AlbumId = 2, Titre = "Idle While" },
new { MorceauId = 8, AlbumId = 2, Titre = "Les Noirs Marchant" },
new { MorceauId = 9, AlbumId = 2, Titre = "Dialogue" },
new { MorceauId = 10, AlbumId = 2, Titre = "Ghetto Lights" },
new { MorceauId = 11, AlbumId = 2, Titre = "Jasper" }
);
}
- Attention toutefois, ici, puisque nous devons donner la clé étrangère, il faut
d'abord ajouter une colonne (une propriété) à notre entité
Morceau
, qui permettra de stocker la clé étrangère pour pointer l'Album
associé :
modelBuilder.Entity<Morceau>().Property<int>("AlbumId");
- Remarquez que À AUCUN MOMENT nous ne précisons les valeurs des propriétés
Album
deMorceau
etMorceaux
deAlbum
. Le simple fait d'utiliser la clé étrangère (propriétéAlbumId
ajoutée précédemment) dansMorceau
est suffisant. - Notez que ce ne sera pas le cas lors d'une utilisation classique de nos classes
(ajout, modification...). Nous ne donnerons plus les identifiants directement mais
les références des propriétés
Morceaux
etAlbum
.
La classe Program
- On affiche tout d'abord le contenu de la base (c'est-à-dire rien ou d'anciennes
données si la migration est faite à partir de
AlbumDBEntites
) ou le stub (si la migration est faite à partir deStubbedContext
). Notez l'utilisation d'Include
dansdb.Albums.Include(a => a.Morceaux)
sinon, lesMorceau
ne sont pas chargés.Include
n'est pas utilisé ensuite dansdb.Morceaux
car lesAlbum
ont déjà été chargés depuis la connexion. Mais on aurait pu faire les accès dans l'autre sens et dans ce cas d'aborddb.Morceaux.Include(m => m.Album)
puis simplementdb.Albums
.
using (AlbumDBEntities db = new AlbumDBEntities())
{
WriteLine("Albums : ");
foreach (var a in db.Albums.Include(a => a.Morceaux))
{
WriteLine($"\t{a.AlbumId}: {a.Titre} (sorti le : {a.DateDeSortie.ToString("d")})");
foreach (var m in a.Morceaux)
{
WriteLine($"\t\t{m.Titre}");
}
}
WriteLine();
WriteLine("Morceaux :");
foreach (var m in db.Morceaux)
{
WriteLine($"\t{m.MorceauId}: {m.Titre} (album : {m.Album.Titre})");
}
//...
}
- La suite de l'exemple ajoute un nouvel
Album
et sesMorceau
puis affiche le contenu de la base de données.
using (AlbumDBEntities db = new AlbumDBEntities())
{
//...
WriteLine("\nAjout d'un album et 6 morceaux...\n");
Album captainMarvel = new Album { Titre = "Captain Marvel", DateDeSortie = new DateTime(1972, 3, 3) };
Morceau[] morceaux = { new Morceau { Titre = "La Fiesta", Album = captainMarvel },
new Morceau { Titre = "Five Hundred Miles High", Album = captainMarvel },
new Morceau { Titre = "Captain Marvel", Album = captainMarvel },
new Morceau { Titre = "Time's Lie", Album = captainMarvel },
new Morceau { Titre = "Lush Life", Album = captainMarvel },
new Morceau { Titre = "Day Waves", Album = captainMarvel }
};
foreach (var m in morceaux)
{
captainMarvel.Morceaux.Add(m);
}
db.Add(captainMarvel);
db.SaveChanges();
}
using (AlbumDBEntities db = new AlbumDBEntities())
{
WriteLine("Albums : ");
foreach (var a in db.Albums.Include(a => a.Morceaux))
{
WriteLine($"\t{a.AlbumId}: {a.Titre} (sorti le : {a.DateDeSortie.ToString("d")})");
foreach (var m in a.Morceaux)
{
WriteLine($"\t\t{m.Titre}");
}
}
WriteLine();
WriteLine("Morceaux :");
foreach (var m in db.Morceaux)
{
WriteLine($"\t{m.MorceauId}: {m.Titre} (album : {m.Album.Titre})");
}
}
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 sous Windows (pour cela, dirigez-vous dans le menu Outils, puis Gestionnaire de package NuGet, puis Console du Gestionnaire de package) ou le Terminal sous MacOSX.
- 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_015_OneToMany_conventions
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 : vous devez préciser la classe fille de
DbContext
à utiliser : soitAlbumDBEntities
, soitStubbedContext
.
- Migration : vous devez préciser la classe fille de
dotnet ef migrations add ex_042_015 --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_015_OneToMany_conventions.
-
Le résultat de l'exécution va ressembler à (si vous avez utilisé
StubbedContext
) :
Albums :
1: Kind of Blue (sorti le : 17/08/1959)
So What
Freddie Freeloader
Blue in Green
All Blues
Flamenco Sketches
2: Dialogue (sorti le : 01/09/1965)
Catta
Idle While
Les Noirs Marchant
Dialogue
Ghetto Lights
Jasper
Morceaux :
1: So What (album : Kind of Blue)
2: Freddie Freeloader (album : Kind of Blue)
3: Blue in Green (album : Kind of Blue)
4: All Blues (album : Kind of Blue)
5: Flamenco Sketches (album : Kind of Blue)
6: Catta (album : Dialogue)
7: Idle While (album : Dialogue)
8: Les Noirs Marchant (album : Dialogue)
9: Dialogue (album : Dialogue)
10: Ghetto Lights (album : Dialogue)
11: Jasper (album : Dialogue)
Ajout d'un album et 6 morceaux...
Albums :
1: Kind of Blue (sorti le : 17/08/1959)
So What
Freddie Freeloader
Blue in Green
All Blues
Flamenco Sketches
2: Dialogue (sorti le : 01/09/1965)
Catta
Idle While
Les Noirs Marchant
Dialogue
Ghetto Lights
Jasper
3: Captain Marvel (sorti le : 03/03/1972)
La Fiesta
Five Hundred Miles High
Captain Marvel
Time's Lie
Lush Life
Day Waves
Morceaux :
1: So What (album : Kind of Blue)
2: Freddie Freeloader (album : Kind of Blue)
3: Blue in Green (album : Kind of Blue)
4: All Blues (album : Kind of Blue)
5: Flamenco Sketches (album : Kind of Blue)
6: Catta (album : Dialogue)
7: Idle While (album : Dialogue)
8: Les Noirs Marchant (album : Dialogue)
9: Dialogue (album : Dialogue)
10: Ghetto Lights (album : Dialogue)
11: Jasper (album : Dialogue)
12: La Fiesta (album : Captain Marvel)
13: Five Hundred Miles High (album : Captain Marvel)
14: Captain Marvel (album : Captain Marvel)
15: Time's Lie (album : Captain Marvel)
16: Lush Life (album : Captain Marvel)
17: Day Waves (album : Captain Marvel)
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 AlbumDBEntities
à la place de StubbedContext
:
dotnet ef migrations add ex_042_015 --context AlbumDBEntities
dotnet ef database update --context AlbumDBEntities
Lors de l'exécution, le résultat sera évidemment différent puisqu'il n'y aura pas les 2 albums du stub. Il pourra ressembler à :
Albums :
Morceaux :
Ajout d'un album et 6 morceaux...
Albums :
1: Captain Marvel (sorti le : 03/03/1972)
La Fiesta
Five Hundred Miles High
Captain Marvel
Time's Lie
Lush Life
Day Waves
Morceaux :
1: La Fiesta (album : Captain Marvel)
2: Five Hundred Miles High (album : Captain Marvel)
3: Captain Marvel (album : Captain Marvel)
4: Time's Lie (album : Captain Marvel)
5: Lush Life (album : Captain Marvel)
6: Day Waves (album : Captain Marvel)
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_015_OneToMany_conventions.Albums.db qui a été généré par l'exécution du
programme et qui se trouve près de ex_042_015_OneToMany_conventions.csproj.
- Choisissez ensuite l'onglet Parcourir les données
- Observez les résultats obtenus des deux tables