using Microsoft.EntityFrameworkCore; using RMuseum.Models.Artifact; using RMuseum.Models.Bookmark; using RMuseum.Models.GanjoorAudio; using RMuseum.Models.UploadSession; using RMuseum.Models.GanjoorIntegration; using RMuseum.Models.ImportJob; using RMuseum.Models.Note; using RSecurityBackend.DbContext; using RSecurityBackend.Models.Auth.Db; using System; using RMuseum.Models.Ganjoor; using RMuseum.Models.Ganjoor.SemanticSearch; using RMuseum.Models.MusicCatalogue; using RMuseum.Models.Accounting; using Microsoft.Extensions.Configuration; using System.IO; using RMuseum.Models.FAQ; using RMuseum.Models.PDFLibrary; using RMuseum.Models.ExternalFTPUpload; namespace RMuseum.DbContext { /// /// Museum Database Context /// public class RMuseumDbContext : RSecurityDbContext { public RMuseumDbContext(DbContextOptions options) : base(options) { IConfigurationRoot configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").AddEnvironmentVariables() // diwan: honour env overrides (Docker) .Build(); if (bool.Parse(configuration["DatabaseMigrate"])) { Database.SetCommandTimeout(18000);//set time out for migration to 5 hours Database.Migrate(); } } /// /// /// /// protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder.Entity() .HasIndex(m => m.FriendlyUrl) .IsUnique(); builder.Entity() .HasIndex(i => new { i.RArtifactMasterRecordId, i.FriendlyUrl }) .IsUnique(); builder.Entity() .HasIndex(i => new { i.RArtifactMasterRecordId, i.Order }) .IsUnique(); builder.Entity() .HasIndex(t => t.FriendlyUrl); builder.Entity() .HasIndex(t => t.FriendlyUrl); builder.Entity() .HasIndex(p => p.GanjoorPostId); builder.Entity() .HasIndex(c => c.FullUrl); builder.Entity() .HasIndex(c => c.FullUrl); builder.Entity() .HasIndex(c => c.FullUrl); builder.Entity() .HasIndex(c => c.Name); builder.Entity() .HasIndex(c => c.Name); builder.Entity() .HasIndex(c => c.CommentDate); builder.Entity() .Property(c => c.ProgressPercent) .HasColumnType("decimal(18,2)"); builder.Entity() .HasIndex(c => c.Status); builder.Entity() .HasIndex(c => c.Id); builder.Entity() .HasIndex(c => c.GanjoorAudioId); builder.Entity() .HasIndex(c => new { c.ReviewStatus, c.GanjoorPostId }); builder.Entity() .HasIndex(c => c.LastModified); builder.Entity() .HasIndex(c => new { c.Published, c.Id }) .IncludeProperties(c => new { c.Name, c.Nickname, c.RImageId }); builder.Entity() .HasIndex(c => new { c.ParentId, c.PoetId }) .IncludeProperties(c => c.Id); builder.Entity() .HasIndex(c => new { c.Approved, c.Rejected }); builder.Entity() .HasIndex(c => new { c.CoverItemIndex, c.Status }); builder.Entity() .HasIndex(m => m.Name) .IsUnique(); // GanjoorPersonRelation has two required FKs to the same table (GanjoorRelatedPerson) - // left at their EF Core default (Cascade, since both are required/non-nullable), SQL // Server refuses to create the second FK with "may cause cycles or multiple cascade // paths". Restricting one side (Person2) is enough to break the ambiguity; deleting a // person that's still referenced by a relation should be prevented at the application // level anyway (via a "still has family tree entries" check), not silently cascaded. builder.Entity() .HasOne(r => r.Person1) .WithMany() .HasForeignKey(r => r.Person1Id) .OnDelete(DeleteBehavior.Restrict); builder.Entity() .HasOne(r => r.Person2) .WithMany() .HasForeignKey(r => r.Person2Id) .OnDelete(DeleteBehavior.Restrict); // same two-required-FKs-to-the-same-table situation as GanjoorPersonRelation above builder.Entity() .HasOne(a => a.Person1) .WithMany() .HasForeignKey(a => a.Person1Id) .OnDelete(DeleteBehavior.Restrict); builder.Entity() .HasOne(a => a.Person2) .WithMany() .HasForeignKey(a => a.Person2Id) .OnDelete(DeleteBehavior.Restrict); // same two-required-FKs-to-the-same-table situation as GanjoorPersonRelation above, plus // a third optional FK to GanjoorPersonRelations itself (ExistingRelationId) - also // restricted, since a relation that still has a pending suggestion against it should be // resolved (or the suggestion rejected) before it can be deleted directly, not silently // orphan the suggestion builder.Entity() .HasOne(s => s.Person1) .WithMany() .HasForeignKey(s => s.Person1Id) .OnDelete(DeleteBehavior.Restrict); builder.Entity() .HasOne(s => s.Person2) .WithMany() .HasForeignKey(s => s.Person2Id) .OnDelete(DeleteBehavior.Restrict); builder.Entity() .HasOne(s => s.ExistingRelation) .WithMany() .HasForeignKey(s => s.ExistingRelationId) .OnDelete(DeleteBehavior.Restrict); // same Restrict treatment as ExistingRelationId above, but for Kind == Affiliation // suggestions targeting a GanjoorPersonAffiliation instead builder.Entity() .HasOne(s => s.ExistingAffiliation) .WithMany() .HasForeignKey(s => s.ExistingAffiliationId) .OnDelete(DeleteBehavior.Restrict); builder.Entity() .HasIndex(b => new { b.UserId, b.PoemId, b.CoupletIndex }); builder.Entity() .HasIndex(n => new { n.NumberingId, n.PoemId, n.CoupletIndex }) .IsUnique(); builder.Entity() .HasIndex(n => new { n.PoemId, n.CoupletIndex }); builder.Entity() .HasIndex(v => v.PoemId);//the next statement causes a drop index in the migration which this line prevents it builder.Entity() .HasIndex(v => new { v.PoemId, v.CoupletIndex }); builder.Entity() .HasIndex(c => new { c.PoemId }); builder.Entity() .HasIndex(c => new { c.FullUrl }); builder.Entity() .Property(c => c.Amount) .HasColumnType("decimal(18,2)"); builder.Entity() .Property(c => c.Remaining) .HasColumnType("decimal(18,2)"); builder.Entity() .Property(c => c.Amount) .HasColumnType("decimal(18,2)"); builder.Entity() .Property(c => c.Amount) .HasColumnType("decimal(18,2)"); builder.Entity() .Property(c => c.Latitude) .HasColumnType("decimal(12,9)"); builder.Entity() .Property(c => c.Longitude) .HasColumnType("decimal(12,9)"); builder.Entity() .HasIndex(v => new { v.RecitationId, v.UserId }) .IsUnique(); builder.Entity() .HasIndex(v => v.UserId); builder.Entity() .HasIndex(v => new { v.UserId, v.PoemId }); builder.Entity() .HasIndex(v => new { v.PoemId, v.Index }); builder.Entity() .HasIndex(v => new { v.RhymeLetters }); builder.Entity() .HasIndex(v => new { v.GanjoorMetreId, v.RhymeLetters }); builder.Entity() .HasIndex(v => new { v.GanjoorMetreId, v.RhymeLetters, v.Id}); builder.Entity() .HasIndex(v => new { v.GanjoorMetreId, v.RhymeLetters, v.SectionType }); builder.Entity() .HasIndex(v => new { v.PoemId, v.SectionIndex }); builder.Entity() .HasIndex(v => new { v.CatId, v.Word }) .IsUnique(); builder.Entity() .HasIndex(v => new { v.CatId }) .IsUnique(); builder.Entity() .Property(e => e.CoupletSummary) .HasMaxLength(4000); builder.Entity() .Property(e => e.Title) .HasMaxLength(1500); builder.Entity() .Property(e => e.FullTitle) .HasMaxLength(1500); builder.Entity() .Property(e => e.UrlSlug) .HasMaxLength(32); builder.Entity() .Property(e => e.RhymeLetters) .HasMaxLength(64); builder.Entity() .Property(e => e.SourceName) .HasMaxLength(64); builder.Entity() .Property(e => e.SourceUrlSlug) .HasMaxLength(16); builder.Entity() .Property(e => e.OldTag) .HasMaxLength(16); builder.Entity() .Property(e => e.OldTagPageUrl) .HasMaxLength(32); builder.Entity() .Property(e => e.Language) .HasMaxLength(8); builder.Entity() .Property(e => e.PoemSummary) .HasMaxLength(3000); builder.Entity() .HasIndex(i => new { i.GanjoorCommentId, i.UserId }) .IsUnique(); builder.Entity() .HasIndex(i => new { i.PoemId, i.UserId }); builder.Entity() .HasIndex(i => new { i.PoemId, i.SortKey }); builder.Entity() .HasIndex(i => new { i.PoemId, i.CommentDate }); } /// /// Picture Files /// public DbSet PictureFiles { get; set; } /// /// Item Attributes /// public DbSet Tags { get; set; } /// /// Artifacts /// public DbSet Artifacts { get; set; } /// /// Items /// public DbSet Items { get; set; } /// /// Import Jobs /// public DbSet ImportJobs { get; set; } /// /// Tags /// public DbSet TagValues { get; set; } /// /// User Bookmarks /// public DbSet UserBookmarks { get; set; } /// /// User Notes /// public DbSet UserNotes { get; set; } /// /// Ganjoor Links /// public DbSet GanjoorLinks { get; set; } /// /// Pinterest Links /// public DbSet PinterestLinks { get; set; } /// /// Ganjoor Audio Files /// public DbSet Recitations { get; set; } /// /// Upload Sessions /// public DbSet UploadSessions { get; set; } /// /// Uploaded files /// public DbSet UploadedFiles { get; set; } /// /// User Recitation Profiles /// public DbSet UserRecitationProfiles { get; set; } /// /// Ganjoor Poets /// public DbSet GanjoorPoets { get; set; } /// /// Ganjoor Categories /// public DbSet GanjoorCategories { get; set; } /// /// Ganjoor Poems /// public DbSet GanjoorPoems { get; set; } /// /// Semantic search query log — see SemanticSearchQueryLog for what is (and deliberately /// isn't) recorded /// public DbSet SemanticSearchQueryLogs { get; set; } /// /// Ganjoor Verses /// public DbSet GanjoorVerses { get; set; } /// /// Narration Publishing Tracker /// public DbSet RecitationPublishingTrackers { get; set; } /// /// Ganjoor Pages /// public DbSet GanjoorPages { get; set; } /// /// Ganjoor Metres /// public DbSet GanjoorMetres { get; set; } /// /// singers /// public DbSet GanjoorSingers { get; set; } /// /// music tracks /// public DbSet GanjoorMusicCatalogueTracks { get; set; } /// /// golha tracks /// public DbSet GolhaTracks { get; set; } /// /// GolhaCollection /// public DbSet GolhaCollections { get; set; } /// /// GolhaPrograms /// public DbSet GolhaPrograms { get; set; } /// /// PoemMusicTracks /// public DbSet GanjoorPoemMusicTracks { get; set; } /// /// Ganjoor Comments /// public DbSet GanjoorComments { get; set; } /// /// Ganjoor Reported Comments /// public DbSet GanjoorReportedComments { get; set; } /// /// Ganjoor Page Snapshots /// public DbSet GanjoorPageSnapshots { get; set; } /// /// Ganjoor Site Bannaers /// public DbSet GanjoorSiteBanners { get; set; } /// /// Ganjoor Health Check Errors /// public DbSet GanjoorHealthCheckErrors { get; set; } /// /// donations /// public DbSet GanjoorDonations { get; set; } /// /// expenses /// public DbSet GanjoorExpenses { get; set; } /// /// donation expenditures /// public DbSet DonationExpenditure { get; set; } /// /// poem corrections /// public DbSet GanjoorPoemCorrections { get; set; } /// /// languages for translation /// public DbSet GanjoorLanguages { get; set; } /// /// ganjoor bookmarks /// public DbSet GanjoorUserBookmarks { get; set; } /// /// ganjoor numbering schemas /// public DbSet GanjoorNumberings { get; set; } /// /// ganjoor verse numbers /// public DbSet GanjoorVerseNumbers { get; set; } /// /// ganjoor half centuries /// public DbSet GanjoorCenturies { get; set; } /// /// ganjoor cities /// public DbSet GanjoorGeoLocations { get; set; } /// /// related poems to each poem (having same rhyme letters and prosody metre) /// public DbSet GanjoorCachedRelatedPoems { get; set; } /// /// Reported User Notes /// public DbSet ReportedUserNotes { get; set; } /// /// recitation error reports /// public DbSet RecitationErrorReports { get; set; } /// /// recitation user up votes /// public DbSet RecitationUserUpVotes { get; set; } /// /// recitation approved mistakes /// public DbSet RecitationApprovedMistakes { get; set; } /// /// probable metres /// public DbSet GanjoorPoemProbableMetres { get; set; } /// /// ganjoor user history track items (stored by his or her choice) /// public DbSet GanjoorUserPoemVisits { get; set; } /// /// suggested spec line for poets /// public DbSet GanjoorPoetSuggestedSpecLines { get; set; } /// /// suggested pictures for poets /// public DbSet GanjoorPoetSuggestedPictures { get; set; } /// /// faq categories /// public DbSet FAQCategories { get; set; } /// /// faq items /// public DbSet FAQItems { get; set; } /// /// Temporary Model contianing duplicated poems information /// public DbSet GanjoorDuplicates { get; set; } /// /// poem sections /// public DbSet GanjoorPoemSections { get; set; } /// /// related sections to each section (having same rhyme letters and prosody metre) /// public DbSet GanjoorCachedRelatedSections { get; set; } /// /// section correctons /// public DbSet GanjoorPoemSectionCorrections { get; set; } /// /// Updating related sections logs /// public DbSet UpdatingRelSectsLogs{ get; set; } /// /// PoemGeoDateTags /// public DbSet PoemGeoDateTags { get; set; } /// /// People tags /// public DbSet GanjoorRelatedPersons { get; set; } /// /// approved kinship edges between people (family tree) - see GanjoorPersonRelation /// public DbSet GanjoorPersonRelations { get; set; } /// /// approved non-family ties between people (e.g. minister-to-king) - see GanjoorPersonAffiliation /// public DbSet GanjoorPersonAffiliations { get; set; } /// /// pending/reviewed suggested edits to an already-approved GanjoorRelatedPerson's own fields - /// see GanjoorPersonEditSuggestion /// public DbSet GanjoorPersonEditSuggestions { get; set; } /// /// pending/reviewed suggested additions, changes or removals of a kinship edge between two /// already-approved people - see GanjoorPersonRelationEditSuggestion /// public DbSet GanjoorPersonRelationEditSuggestions { get; set; } /// /// Books (PDF Library) /// public DbSet Books { get; set; } /// /// Authurs /// public DbSet Authors { get; set; } /// /// Multi Volume PDF Collections /// public DbSet MultiVolumePDFCollections { get; set; } /// /// PDF Books /// public DbSet PDFBooks { get; set; } /// /// PDF Pages /// public DbSet PDFPages { get; set; } /// /// PDF Sources /// public DbSet PDFSources { get; set; } /// /// Queued FTP Uploads /// public DbSet QueuedFTPUploads { get; set; } /// /// PDF Ganjoor Links /// public DbSet PDFGanjoorLinks { get; set; } /// /// OCR Queue Items /// public DbSet OCRQueuedItems { get; set; } /// /// PDF Download Queue /// public DbSet QueuedPDFBooks { get; set; } /// /// Related Poems /// public DbSet GanjoorQuotedPoems { get; set; } /// /// discover quoted q items /// public DbSet DiscoverQuotedQueueItems { get; set; } /// /// paper sources /// public DbSet GanjoorPaperSources { get; set; } /// /// digital sources /// public DbSet DigitalSources { get; set; } /// /// Category Word Counts /// public DbSet CategoryWordCounts { get; set; } /// /// Category Word Count Summaries /// public DbSet CategoryWordCountSummaries { get; set; } /// /// ganjoor cat corrections /// public DbSet GanjoorCatCorrections { get; set; } /// /// comment reactions /// public DbSet GanjoorCommentReactions { get; set; } } }