Ajouter la liste d'envies personnelle, son export et la bibliographie par auteur

La liste d'envies vit dans une table séparée (LivreSouhaite) plutôt que dans un
statut de plus sur Livre : un livre souhaité n'est pas possédé, et le loger dans
Livres l'aurait fait entrer dans le catalogue, les compteurs et les prêts, au
prix d'un « et qui n'est pas souhaité » à répéter dans chaque lecture. La portée
est personnelle, comme le statut de lecture — mais ici Utilisateur est une vraie
frontière : toute lecture filtre dessus.

Bibliographie : SRU BnF interrogé par bib.author, vérifié le 2026-08-18. Deux
filtres mesurés sur des réponses réelles sont indispensables — le type de
document (l'index mêle livres audio, jeux et spectacles) et surtout l'auteur
réel de la notice, « all » rapprochant les mots sur l'ensemble des auteurs :
« Émile Zola » remonte sinon toute l'œuvre de sa fille Denise Le Blond-Zola.
Les rééditions sont regroupées par clé d'œuvre (183 notices Werber -> 51
œuvres). Le rapprochement avec l'étagère se fait par titre, pas par ISBN, qui
désigne une édition et non une œuvre ; ses limites sont dites à l'écran.

Export en deux formats, tous deux du texte sans dépendance : .txt groupé par
auteur pour la librairie, .csv à séparateur point-virgule et BOM pour le
tableur.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mathieu
2026-08-18 13:59:06 +02:00
co-authored by Claude Opus 5
parent 3a5a3a7763
commit 8b8fe3be6e
27 changed files with 3939 additions and 0 deletions
+31
View File
@@ -17,6 +17,13 @@ public class MaBibliDbContext(DbContextOptions<MaBibliDbContext> options) : DbCo
public DbSet<Pret> Prets => Set<Pret>();
/// <summary>
/// Liste d'envies, <b>personnelle</b>. Table séparée des <see cref="Livres"/> : un livre
/// souhaité n'est pas un livre possédé, et ne doit apparaître ni au catalogue, ni dans les
/// compteurs, ni dans les prêts.
/// </summary>
public DbSet<LivreSouhaite> LivresSouhaites => Set<LivreSouhaite>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
@@ -90,6 +97,30 @@ public class MaBibliDbContext(DbContextOptions<MaBibliDbContext> options) : DbCo
refus.HasIndex(r => new { r.AuteurAId, r.AuteurBId }).IsUnique();
});
modelBuilder.Entity<LivreSouhaite>(souhait =>
{
souhait.Property(s => s.Utilisateur).IsRequired();
souhait.Property(s => s.Titre).IsRequired();
souhait.Property(s => s.TitreNormalise).IsRequired();
// Jamais nullable : SQLite tient deux NULL pour distincts, et l'unicité ci-dessous
// laisserait alors passer autant de doublons qu'on veut sur les envies sans auteur.
souhait.Property(s => s.AuteurNormalise).IsRequired().HasDefaultValue(string.Empty);
// Toute lecture part de là : la liste est personnelle, on la parcourt par personne.
souhait.HasIndex(s => s.Utilisateur, "IX_LivresSouhaites_Utilisateur");
// Une même œuvre ne s'ajoute qu'une fois par personne — l'écran de bibliographie
// rend le double clic facile. L'auteur fait partie de la clé : deux auteurs peuvent
// avoir publié deux « Œuvres » différentes, et l'un ne doit pas bloquer l'autre.
// Deux personnes peuvent en revanche souhaiter le même livre, d'où l'utilisateur
// en tête de l'index.
souhait.HasIndex(
s => new { s.Utilisateur, s.TitreNormalise, s.AuteurNormalise },
"IX_LivresSouhaites_Utilisateur_Oeuvre")
.IsUnique();
});
modelBuilder.Entity<Pret>(pret =>
{
pret.Property(p => p.Emprunteur).IsRequired();