using Microsoft.EntityFrameworkCore; namespace MangaReader.Core.Data; public class Manga { public int MangaId { get; set; } public required string Slug { get; set; } public required string Title { get; set; } public string? Description { get; set; } public virtual ICollection Covers { get; set; } public virtual ICollection Titles { get; set; } public virtual ICollection Sources { get; set; } public virtual ICollection Genres { get; set; } public virtual ICollection Chapters { get; set; } public Manga() { Covers = new HashSet(); Titles = new HashSet(); Sources = new HashSet(); Genres = new HashSet(); Chapters = new HashSet(); } } public class MangaCover { public int MangaCoverId { get; set; } public int MangaId { get; set; } public required Manga Manga { get; set; } public required Guid Guid { get; set; } public required string FileExtension { get; set; } public string? Description { get; set; } public bool IsPrimary { get; set; } } public class MangaTitle { public int MangaTitleId { get; set; } public int MangaId { get; set; } public required Manga Manga { get; set; } public required string TitleEntry { get; set; } public TitleType TitleType { get; set; } } public enum TitleType { Primary, OfficialTranslation, FanTranslation, Synonym, Abbreviation, Romaji, Japanese } public class Source { public int SourceId { get; set; } public required string Name { get; set; } } public class MangaSource { public int MangaId { get; set; } public required Manga Manga { get; set; } public int SourceId { get; set; } public required Source Source { get; set; } public required string Url { get; set; } } public class Genre { public int GenreId { get; set; } public required string Name { get; set; } } public class MangaGenre { public int MangaId { get; set; } public required Manga Manga { get; set; } public int GenreId { get; set; } public required Genre Genre { get; set; } } public class MangaChapter { public int MangaChapterId { get; set; } public int MangaId { get; set; } public required Manga Manga { get; set; } public int? VolumeNumber { get; set; } public int ChapterNumber { get; set; } public string? Title { get; set; } public virtual ICollection Sources { get; set; } = []; public virtual ICollection Pages { get; set; } = []; } public class ChapterSource { public int MangaChapterId { get; set; } public required MangaChapter Chapter { get; set; } public int SourceId { get; set; } public required Source Source { get; set; } public required string Url { get; set; } } public class ChapterPage { public int ChapterPageId { get; set; } public int MangaChapterId { get; set; } public required MangaChapter MangaChapter { get; set; } public int PageNumber { get; set; } } public class MangaContext(DbContextOptions options) : DbContext(options) { public DbSet Mangas { get; set; } public DbSet MangaCovers { get; set; } public DbSet MangaTitles { get; set; } public DbSet Sources { get; set; } public DbSet MangaSources { get; set; } public DbSet Genres { get; set; } public DbSet MangaGenres { get; set; } public DbSet MangaChapters { get; set; } public DbSet ChapterSources { get; set; } public DbSet ChapterPages { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); ConfigureManga(modelBuilder); ConfigureMangaCover(modelBuilder); ConfigureMangaTitle(modelBuilder); ConfigureSource(modelBuilder); ConfigureMangaSource(modelBuilder); ConfigureGenre(modelBuilder); ConfigureMangaGenre(modelBuilder); ConfigureMangaChapter(modelBuilder); ConfigureChapterSource(modelBuilder); ConfigureChapterPage(modelBuilder); } private static void ConfigureManga(ModelBuilder modelBuilder) { modelBuilder .Entity() .HasKey(x => x.MangaId); modelBuilder.Entity() .HasIndex(x => x.Slug) .IsUnique(); } private static void ConfigureMangaCover(ModelBuilder modelBuilder) { modelBuilder .Entity() .HasKey(x => x.MangaCoverId); modelBuilder .Entity() .HasOne(x => x.Manga) .WithMany(x => x.Covers) .HasForeignKey(x => x.MangaId) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasIndex(x => x.Guid) .IsUnique(); //modelBuilder // .Entity() // .HasIndex(x => new { x.MangaId, x.IsPrimary }) // .IsUnique() // .HasFilter("[IsPrimary] = 1"); // Enforce only one primary cover per manga } private static void ConfigureMangaTitle(ModelBuilder modelBuilder) { modelBuilder .Entity() .HasKey(mangaTitle => mangaTitle.MangaTitleId); modelBuilder.Entity() .HasIndex(mangaTitle => new { mangaTitle.MangaId, mangaTitle.TitleEntry }) .IsUnique(); modelBuilder .Entity() .HasIndex(mangaTitle => mangaTitle.TitleEntry); modelBuilder .Entity() .HasOne(x => x.Manga) .WithMany(x => x.Titles) .HasForeignKey(x => x.MangaId) .OnDelete(DeleteBehavior.Cascade); } private static void ConfigureSource(ModelBuilder modelBuilder) { modelBuilder .Entity() .HasKey(x => x.SourceId); modelBuilder .Entity() .HasIndex(x => x.Name) .IsUnique(true); } private static void ConfigureMangaSource(ModelBuilder modelBuilder) { modelBuilder .Entity() .HasKey(mangaSource => new { mangaSource.MangaId, mangaSource.SourceId }); modelBuilder.Entity() .HasIndex(x => x.Url) .IsUnique(); modelBuilder .Entity() .HasOne(x => x.Manga) .WithMany(x => x.Sources) .HasForeignKey(x => x.MangaId) .OnDelete(DeleteBehavior.Cascade); } private static void ConfigureGenre(ModelBuilder modelBuilder) { modelBuilder .Entity() .HasKey(x => x.GenreId); modelBuilder .Entity() .HasIndex(x => x.Name) .IsUnique(true); } private static void ConfigureMangaGenre(ModelBuilder modelBuilder) { modelBuilder .Entity() .HasKey(mangaGenre => new { mangaGenre.MangaId, mangaGenre.GenreId }); modelBuilder .Entity() .HasOne(x => x.Manga) .WithMany(x => x.Genres) .HasForeignKey(x => x.MangaId) .OnDelete(DeleteBehavior.Cascade); } private static void ConfigureMangaChapter(ModelBuilder modelBuilder) { modelBuilder .Entity() .HasKey(x => x.MangaChapterId); modelBuilder .Entity() .HasOne(x => x.Manga) .WithMany(x => x.Chapters) .HasForeignKey(x => x.MangaId) .OnDelete(DeleteBehavior.Cascade); } private static void ConfigureChapterSource(ModelBuilder modelBuilder) { modelBuilder .Entity() .HasKey(chapterSource => new { chapterSource.MangaChapterId, chapterSource.SourceId }); modelBuilder .Entity() .HasOne(x => x.Chapter) .WithMany(x => x.Sources) .HasForeignKey(x => x.MangaChapterId) .OnDelete(DeleteBehavior.Cascade); } private static void ConfigureChapterPage(ModelBuilder modelBuilder) { modelBuilder .Entity() .HasKey(chapterPage => chapterPage.ChapterPageId); modelBuilder .Entity() .HasIndex(chapterPage => new { chapterPage.MangaChapterId, chapterPage.PageNumber }) .IsUnique(true); modelBuilder .Entity() .HasOne(x => x.MangaChapter) .WithMany(x => x.Pages) .HasForeignKey(x => x.MangaChapterId) .OnDelete(DeleteBehavior.Cascade); } }