Fix Surah seed tracking conflict on API startup retries.
build-and-deploy / deploy (push) Has been cancelled
build-and-deploy / deploy (push) Has been cancelled
Use idempotent seed, fresh DbContext per retry, and explicit Surah/Tafsir keys.
This commit is contained in:
@@ -40,14 +40,15 @@ builder.Services.AddOpenApi();
|
|||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
using (var scope = app.Services.CreateScope())
|
|
||||||
{
|
{
|
||||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
var audioRoot = app.Configuration["AudioRoot"] ?? "/data/audio";
|
||||||
for (var attempt = 1; ; attempt++)
|
for (var attempt = 1; ; attempt++)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var audioRoot = app.Configuration["AudioRoot"] ?? "/data/audio";
|
// Fresh scope each attempt so a failed seed cannot leave tracked entities.
|
||||||
|
using var scope = app.Services.CreateScope();
|
||||||
|
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||||
await DbSeeder.SeedAsync(db, audioRoot);
|
await DbSeeder.SeedAsync(db, audioRoot);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(op
|
|||||||
|
|
||||||
modelBuilder.Entity<Tafsir>(e =>
|
modelBuilder.Entity<Tafsir>(e =>
|
||||||
{
|
{
|
||||||
|
e.Property(x => x.Id).ValueGeneratedNever();
|
||||||
e.HasIndex(x => x.Slug).IsUnique();
|
e.HasIndex(x => x.Slug).IsUnique();
|
||||||
e.Property(x => x.Title).HasMaxLength(200);
|
e.Property(x => x.Title).HasMaxLength(200);
|
||||||
e.Property(x => x.Author).HasMaxLength(120);
|
e.Property(x => x.Author).HasMaxLength(120);
|
||||||
@@ -35,6 +36,7 @@ public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(op
|
|||||||
|
|
||||||
modelBuilder.Entity<Surah>(e =>
|
modelBuilder.Entity<Surah>(e =>
|
||||||
{
|
{
|
||||||
|
e.Property(x => x.Id).ValueGeneratedNever();
|
||||||
e.HasIndex(x => x.Number).IsUnique();
|
e.HasIndex(x => x.Number).IsUnique();
|
||||||
e.Property(x => x.NameAr).HasMaxLength(80);
|
e.Property(x => x.NameAr).HasMaxLength(80);
|
||||||
e.Property(x => x.NameFa).HasMaxLength(80);
|
e.Property(x => x.NameFa).HasMaxLength(80);
|
||||||
|
|||||||
@@ -43,12 +43,13 @@ public static class DbSeeder
|
|||||||
public static async Task SeedAsync(AppDbContext db, string? audioRoot = null, CancellationToken ct = default)
|
public static async Task SeedAsync(AppDbContext db, string? audioRoot = null, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await db.Database.MigrateAsync(ct);
|
await db.Database.MigrateAsync(ct);
|
||||||
|
db.ChangeTracker.Clear();
|
||||||
|
|
||||||
if (!await db.Surahs.AnyAsync(ct))
|
var existingSurahIds = (await db.Surahs.AsNoTracking().Select(s => s.Id).ToListAsync(ct)).ToHashSet();
|
||||||
{
|
|
||||||
for (var i = 0; i < SurahNames.Length; i++)
|
for (var i = 0; i < SurahNames.Length; i++)
|
||||||
{
|
{
|
||||||
var n = i + 1;
|
var n = i + 1;
|
||||||
|
if (existingSurahIds.Contains(n)) continue;
|
||||||
db.Surahs.Add(new Surah
|
db.Surahs.Add(new Surah
|
||||||
{
|
{
|
||||||
Id = n,
|
Id = n,
|
||||||
@@ -57,10 +58,12 @@ public static class DbSeeder
|
|||||||
NameFa = SurahNames[i].Fa
|
NameFa = SurahNames[i].Fa
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (db.ChangeTracker.HasChanges())
|
||||||
await db.SaveChangesAsync(ct);
|
await db.SaveChangesAsync(ct);
|
||||||
}
|
|
||||||
|
|
||||||
if (!await db.Tafsirs.AnyAsync(ct))
|
db.ChangeTracker.Clear();
|
||||||
|
|
||||||
|
if (!await db.Tafsirs.AsNoTracking().AnyAsync(t => t.Id == GhatrehChekaniId, ct))
|
||||||
{
|
{
|
||||||
db.Tafsirs.Add(new Tafsir
|
db.Tafsirs.Add(new Tafsir
|
||||||
{
|
{
|
||||||
@@ -73,6 +76,7 @@ public static class DbSeeder
|
|||||||
await db.SaveChangesAsync(ct);
|
await db.SaveChangesAsync(ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
db.ChangeTracker.Clear();
|
||||||
await SyncEpisodesFromAudioAsync(db, audioRoot, ct);
|
await SyncEpisodesFromAudioAsync(db, audioRoot, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,14 +85,14 @@ public static class DbSeeder
|
|||||||
if (string.IsNullOrWhiteSpace(audioRoot) || !Directory.Exists(audioRoot))
|
if (string.IsNullOrWhiteSpace(audioRoot) || !Directory.Exists(audioRoot))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var tafsir = await db.Tafsirs.FirstOrDefaultAsync(t => t.Id == GhatrehChekaniId, ct);
|
if (!await db.Tafsirs.AsNoTracking().AnyAsync(t => t.Id == GhatrehChekaniId, ct))
|
||||||
if (tafsir is null) return;
|
return;
|
||||||
|
|
||||||
var existing = await db.Episodes
|
var existingSet = (await db.Episodes.AsNoTracking()
|
||||||
.Where(e => e.TafsirId == GhatrehChekaniId)
|
.Where(e => e.TafsirId == GhatrehChekaniId)
|
||||||
.Select(e => e.AudioUrl)
|
.Select(e => e.AudioUrl)
|
||||||
.ToListAsync(ct);
|
.ToListAsync(ct))
|
||||||
var existingSet = existing.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var audioFiles = Directory.EnumerateFiles(audioRoot, "*.*", SearchOption.AllDirectories)
|
var audioFiles = Directory.EnumerateFiles(audioRoot, "*.*", SearchOption.AllDirectories)
|
||||||
.Where(f => f.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase)
|
.Where(f => f.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase)
|
||||||
@@ -100,7 +104,7 @@ public static class DbSeeder
|
|||||||
|
|
||||||
if (audioFiles.Count == 0) return;
|
if (audioFiles.Count == 0) return;
|
||||||
|
|
||||||
var sort = existing.Count;
|
var sort = existingSet.Count;
|
||||||
var added = 0;
|
var added = 0;
|
||||||
foreach (var file in audioFiles)
|
foreach (var file in audioFiles)
|
||||||
{
|
{
|
||||||
@@ -122,10 +126,18 @@ public static class DbSeeder
|
|||||||
SortOrder = sort,
|
SortOrder = sort,
|
||||||
Summary = null
|
Summary = null
|
||||||
});
|
});
|
||||||
|
existingSet.Add(relative);
|
||||||
added++;
|
added++;
|
||||||
|
|
||||||
|
// batch inserts to avoid huge change tracker
|
||||||
|
if (added % 200 == 0)
|
||||||
|
{
|
||||||
|
await db.SaveChangesAsync(ct);
|
||||||
|
db.ChangeTracker.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (added > 0)
|
if (db.ChangeTracker.HasChanges())
|
||||||
await db.SaveChangesAsync(ct);
|
await db.SaveChangesAsync(ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,10 +161,8 @@ public static class DbSeeder
|
|||||||
|
|
||||||
private static int GuessAyahNumber(string fileName)
|
private static int GuessAyahNumber(string fileName)
|
||||||
{
|
{
|
||||||
// patterns: ..._001, -1, .1, ayah01
|
|
||||||
var matches = System.Text.RegularExpressions.Regex.Matches(fileName, @"(\d+)");
|
var matches = System.Text.RegularExpressions.Regex.Matches(fileName, @"(\d+)");
|
||||||
if (matches.Count == 0) return 1;
|
if (matches.Count == 0) return 1;
|
||||||
// prefer last number group as ayah when multiple
|
|
||||||
if (int.TryParse(matches[^1].Value, out var n) && n > 0)
|
if (int.TryParse(matches[^1].Value, out var n) && n > 0)
|
||||||
return n;
|
return n;
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
Generated
+396
@@ -0,0 +1,396 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using TafsirQuran.Infrastructure.Persistence;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TafsirQuran.Infrastructure.Persistence.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AppDbContext))]
|
||||||
|
[Migration("20261009192702_SurahExplicitIds")]
|
||||||
|
partial class SurahExplicitIds
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "9.0.10")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||||
|
|
||||||
|
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.AppUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.HasColumnType("datetimeoffset");
|
||||||
|
|
||||||
|
b.Property<string>("DisplayName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("nvarchar(128)");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Email")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.Ayah", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<int>("Number")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("SurahId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("TextAr")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("TextFa")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SurahId", "Number")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Ayahs");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.Bookmark", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.HasColumnType("datetimeoffset");
|
||||||
|
|
||||||
|
b.Property<string>("DeviceId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("nvarchar(64)");
|
||||||
|
|
||||||
|
b.Property<Guid>("EpisodeId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("Note")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("nvarchar(500)");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("EpisodeId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.HasIndex("DeviceId", "UserId", "EpisodeId")
|
||||||
|
.IsUnique()
|
||||||
|
.HasFilter("[UserId] IS NOT NULL");
|
||||||
|
|
||||||
|
b.ToTable("Bookmarks");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.Favorite", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.HasColumnType("datetimeoffset");
|
||||||
|
|
||||||
|
b.Property<string>("DeviceId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("nvarchar(64)");
|
||||||
|
|
||||||
|
b.Property<Guid>("EpisodeId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("EpisodeId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.HasIndex("DeviceId", "UserId", "EpisodeId")
|
||||||
|
.IsUnique()
|
||||||
|
.HasFilter("[UserId] IS NOT NULL");
|
||||||
|
|
||||||
|
b.ToTable("Favorites");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.ListeningProgress", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("DeviceId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("nvarchar(64)");
|
||||||
|
|
||||||
|
b.Property<Guid>("EpisodeId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<double>("PositionSeconds")
|
||||||
|
.HasColumnType("float");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("UpdatedAt")
|
||||||
|
.HasColumnType("datetimeoffset");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("EpisodeId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.HasIndex("DeviceId", "UserId");
|
||||||
|
|
||||||
|
b.ToTable("ListeningProgresses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.Surah", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("NameAr")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(80)
|
||||||
|
.HasColumnType("nvarchar(80)");
|
||||||
|
|
||||||
|
b.Property<string>("NameFa")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(80)
|
||||||
|
.HasColumnType("nvarchar(80)");
|
||||||
|
|
||||||
|
b.Property<int>("Number")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Number")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Surahs");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.Tafsir", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("Author")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(120)
|
||||||
|
.HasColumnType("nvarchar(120)");
|
||||||
|
|
||||||
|
b.Property<string>("CoverUrl")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsPublished")
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(120)
|
||||||
|
.HasColumnType("nvarchar(120)");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("nvarchar(200)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Slug")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Tafsirs");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.TafsirEpisode", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("AudioUrl")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<int>("AyahNumber")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("DurationSeconds")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("SortOrder")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Summary")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<int>("SurahId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<Guid>("TafsirId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(300)
|
||||||
|
.HasColumnType("nvarchar(300)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SurahId");
|
||||||
|
|
||||||
|
b.HasIndex("TafsirId", "SortOrder");
|
||||||
|
|
||||||
|
b.ToTable("Episodes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.Ayah", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TafsirQuran.Domain.Entities.Surah", "Surah")
|
||||||
|
.WithMany("Ayahs")
|
||||||
|
.HasForeignKey("SurahId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Surah");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.Bookmark", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TafsirQuran.Domain.Entities.TafsirEpisode", "Episode")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("EpisodeId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TafsirQuran.Domain.Entities.AppUser", "User")
|
||||||
|
.WithMany("Bookmarks")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("Episode");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.Favorite", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TafsirQuran.Domain.Entities.TafsirEpisode", "Episode")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("EpisodeId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TafsirQuran.Domain.Entities.AppUser", "User")
|
||||||
|
.WithMany("Favorites")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("Episode");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.ListeningProgress", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TafsirQuran.Domain.Entities.TafsirEpisode", "Episode")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("EpisodeId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TafsirQuran.Domain.Entities.AppUser", "User")
|
||||||
|
.WithMany("ListeningProgresses")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("Episode");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.TafsirEpisode", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TafsirQuran.Domain.Entities.Surah", "Surah")
|
||||||
|
.WithMany("Episodes")
|
||||||
|
.HasForeignKey("SurahId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TafsirQuran.Domain.Entities.Tafsir", "Tafsir")
|
||||||
|
.WithMany("Episodes")
|
||||||
|
.HasForeignKey("TafsirId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Surah");
|
||||||
|
|
||||||
|
b.Navigation("Tafsir");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.AppUser", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Bookmarks");
|
||||||
|
|
||||||
|
b.Navigation("Favorites");
|
||||||
|
|
||||||
|
b.Navigation("ListeningProgresses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.Surah", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Ayahs");
|
||||||
|
|
||||||
|
b.Navigation("Episodes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.Tafsir", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Episodes");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TafsirQuran.Infrastructure.Persistence.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class SurahExplicitIds : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "Id",
|
||||||
|
table: "Surahs",
|
||||||
|
type: "int",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "int")
|
||||||
|
.OldAnnotation("SqlServer:Identity", "1, 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "Id",
|
||||||
|
table: "Surahs",
|
||||||
|
type: "int",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "int")
|
||||||
|
.Annotation("SqlServer:Identity", "1, 1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -187,11 +187,8 @@ namespace TafsirQuran.Infrastructure.Persistence.Migrations
|
|||||||
modelBuilder.Entity("TafsirQuran.Domain.Entities.Surah", b =>
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.Surah", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("NameAr")
|
b.Property<string>("NameAr")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(80)
|
.HasMaxLength(80)
|
||||||
@@ -216,7 +213,6 @@ namespace TafsirQuran.Infrastructure.Persistence.Migrations
|
|||||||
modelBuilder.Entity("TafsirQuran.Domain.Entities.Tafsir", b =>
|
modelBuilder.Entity("TafsirQuran.Domain.Entities.Tafsir", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("uniqueidentifier");
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
b.Property<string>("Author")
|
b.Property<string>("Author")
|
||||||
|
|||||||
Reference in New Issue
Block a user