Ajouter les sagas et cycles, avec leurs tomes manquants
Première relation entre livres du projet. Une série contient des séries (un cycle EST une série de séries) et des PLACES dans l'ordre de lecture — pas des livres : une place sans livre est le trou qu'on vient voir. L'ordre est stocké, jamais déduit d'une année : une préquelle se lit avant le livre paru dix ans plus tôt. Les tomes non possédés se saisissent à la main, aucune source ne donnant l'ordre de lecture d'une saga. Le titre de la place survit à la suppression du livre (SetNull, pas de cascade), sans quoi perdre un exemplaire effacerait le tome 3 de la série. Les séries sont communes au foyer. Seule exception : la mise en envies d'un tome manquant, qui écrit dans une liste personnelle — c'est le seul point où les deux portées se rencontrent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,14 @@ public class MaBibliDbContext(DbContextOptions<MaBibliDbContext> options) : DbCo
|
||||
/// </summary>
|
||||
public DbSet<LivreSouhaite> LivresSouhaites => Set<LivreSouhaite>();
|
||||
|
||||
/// <summary>
|
||||
/// Sagas, cycles et séries. <b>Communs au foyer</b>, comme le catalogue : l'ordre de lecture
|
||||
/// est une propriété de l'œuvre, pas du lecteur.
|
||||
/// </summary>
|
||||
public DbSet<Serie> Series => Set<Serie>();
|
||||
|
||||
public DbSet<ElementSerie> ElementsSerie => Set<ElementSerie>();
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
@@ -121,6 +129,54 @@ public class MaBibliDbContext(DbContextOptions<MaBibliDbContext> options) : DbCo
|
||||
.IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Serie>(serie =>
|
||||
{
|
||||
serie.Property(s => s.Titre).IsRequired();
|
||||
serie.Property(s => s.TitreNormalise).IsRequired();
|
||||
|
||||
// Une série, une fiche. Voir l'entité : l'unicité est GLOBALE et non par parent,
|
||||
// le parent étant nullable et deux NULL étant distincts pour SQLite.
|
||||
serie.HasIndex(s => s.TitreNormalise).IsUnique();
|
||||
|
||||
// SetNull et non Cascade : supprimer un cycle ne doit pas emporter les trilogies
|
||||
// qu'il contient — ce sont de vraies séries de vrais livres, qui se tiennent seules.
|
||||
serie.HasOne(s => s.SerieParente)
|
||||
.WithMany(s => s.SousSeries)
|
||||
.HasForeignKey(s => s.SerieParenteId)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
serie.HasIndex(s => s.SerieParenteId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<ElementSerie>(element =>
|
||||
{
|
||||
element.Property(e => e.Titre).IsRequired();
|
||||
|
||||
element.HasOne(e => e.Serie)
|
||||
.WithMany(s => s.Elements)
|
||||
.HasForeignKey(e => e.SerieId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
// ⚠️ SetNull, surtout pas Cascade : supprimer un livre du catalogue doit laisser sa
|
||||
// place dans la saga, devenue un trou nommé. Cascade effacerait le tome 3 de la
|
||||
// série parce qu'on a prêté puis perdu son exemplaire.
|
||||
element.HasOne(e => e.Livre)
|
||||
.WithMany()
|
||||
.HasForeignKey(e => e.LivreId)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
element.HasIndex(e => e.SerieId, "IX_ElementsSerie_SerieId");
|
||||
|
||||
// Un même livre ne tient qu'une place dans une série donnée. Index PARTIEL, comme
|
||||
// pour les prêts : les positions sans livre (les trous) doivent pouvoir se répéter
|
||||
// autant que nécessaire, et deux NULL passeraient de toute façon.
|
||||
// Un livre peut en revanche appartenir à PLUSIEURS séries — une intégrale, une
|
||||
// série, un cycle — d'où l'absence d'unicité sur LivreId seul.
|
||||
element.HasIndex(e => new { e.SerieId, e.LivreId }, "IX_ElementsSerie_SerieId_LivreId")
|
||||
.IsUnique()
|
||||
.HasFilter("\"LivreId\" IS NOT NULL");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Pret>(pret =>
|
||||
{
|
||||
pret.Property(p => p.Emprunteur).IsRequired();
|
||||
|
||||
Reference in New Issue
Block a user