using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using ROLAC.API.Entities; namespace ROLAC.API.Data; public class AppDbContext : IdentityDbContext { public AppDbContext(DbContextOptions options) : base(options) { } public DbSet RefreshTokens => Set(); public DbSet Members => Set(); public DbSet FamilyUnits => Set(); public DbSet GivingCategories => Set(); public DbSet OfferingSessions => Set(); public DbSet Givings => Set(); protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); // ── RefreshToken (unchanged) ──────────────────────────────────────── builder.Entity(entity => { entity.HasKey(e => e.Id); entity.HasIndex(e => e.TokenHash).IsUnique(); entity.Property(e => e.TokenHash).HasMaxLength(64).IsRequired(); entity.Property(e => e.UserId).HasMaxLength(450).IsRequired(); entity.Property(e => e.DeviceInfo).HasMaxLength(200); entity.Property(e => e.IpAddress).HasMaxLength(45); entity.Property(e => e.ReplacedByHash).HasMaxLength(64); entity.HasOne(e => e.User).WithMany(u => u.RefreshTokens) .HasForeignKey(e => e.UserId).OnDelete(DeleteBehavior.Cascade); entity.Ignore(e => e.IsExpired); entity.Ignore(e => e.IsRevoked); entity.Ignore(e => e.IsActive); }); // ── AppUser (unchanged + new unique index on MemberId) ────────────── builder.Entity(entity => { entity.Property(e => e.LanguagePreference).HasMaxLength(10).HasDefaultValue("en"); // Nullable unique: one member ↔ one user account, but member can have no account entity.HasIndex(e => e.MemberId).IsUnique() .HasFilter("\"MemberId\" IS NOT NULL"); }); // ── AppRole (unchanged) ───────────────────────────────────────────── builder.Entity(entity => { entity.Property(e => e.Description).HasMaxLength(500); }); // ── FamilyUnit ────────────────────────────────────────────────────── builder.Entity(entity => { entity.Property(e => e.FamilyName_en).HasMaxLength(200); entity.Property(e => e.FamilyName_zh).HasMaxLength(200); }); // ── Member ────────────────────────────────────────────────────────── builder.Entity(entity => { entity.HasQueryFilter(m => !m.IsDeleted); entity.Property(e => e.FirstName_en).HasMaxLength(100).IsRequired(); entity.Property(e => e.LastName_en).HasMaxLength(100).IsRequired(); entity.Property(e => e.NickName).HasMaxLength(100); entity.Property(e => e.FirstName_zh).HasMaxLength(100); entity.Property(e => e.LastName_zh).HasMaxLength(100); entity.Property(e => e.Gender).HasMaxLength(10); entity.Property(e => e.BaptismChurch).HasMaxLength(200); entity.Property(e => e.Email).HasMaxLength(200); entity.Property(e => e.PhoneCell).HasMaxLength(30); entity.Property(e => e.PhoneHome).HasMaxLength(30); entity.Property(e => e.Address).HasMaxLength(500); entity.Property(e => e.City).HasMaxLength(100); entity.Property(e => e.State).HasMaxLength(50); entity.Property(e => e.ZipCode).HasMaxLength(20); entity.Property(e => e.Country).HasMaxLength(100).HasDefaultValue("USA"); entity.Property(e => e.PhotoBlobPath).HasMaxLength(500); entity.Property(e => e.Status).HasMaxLength(20).HasDefaultValue("Member"); entity.Property(e => e.LanguagePreference).HasMaxLength(10).HasDefaultValue("en"); entity.Property(e => e.CreatedBy).HasMaxLength(450); entity.Property(e => e.UpdatedBy).HasMaxLength(450); entity.Property(e => e.DeletedBy).HasMaxLength(450); entity.HasIndex(e => e.Status).HasFilter("\"IsDeleted\" = false"); entity.HasIndex(e => e.Email).HasFilter("\"Email\" IS NOT NULL"); entity.HasIndex(e => e.FamilyUnitId); entity.HasOne(e => e.FamilyUnit).WithMany() .HasForeignKey(e => e.FamilyUnitId).OnDelete(DeleteBehavior.SetNull); }); // ── GivingCategory ─────────────────────────────────────────────────── builder.Entity(entity => { entity.Property(e => e.Name_en).HasMaxLength(200).IsRequired(); entity.Property(e => e.Name_zh).HasMaxLength(200); entity.Property(e => e.Description_en).HasMaxLength(500); entity.Property(e => e.Description_zh).HasMaxLength(500); entity.Property(e => e.CreatedBy).HasMaxLength(450); entity.Property(e => e.UpdatedBy).HasMaxLength(450); }); // ── OfferingSession ────────────────────────────────────────────────── builder.Entity(entity => { entity.Property(e => e.Status).HasMaxLength(20).HasDefaultValue("Draft"); entity.Property(e => e.CashTotal).HasColumnType("decimal(18,2)"); entity.Property(e => e.CheckTotal).HasColumnType("decimal(18,2)"); entity.Property(e => e.SystemTotal).HasColumnType("decimal(18,2)"); entity.Property(e => e.Difference).HasColumnType("decimal(18,2)"); entity.Property(e => e.SubmittedBy).HasMaxLength(450); entity.Property(e => e.ReconciledBy).HasMaxLength(450); entity.Property(e => e.CreatedBy).HasMaxLength(450); entity.Property(e => e.UpdatedBy).HasMaxLength(450); entity.HasIndex(e => e.SessionDate).IsUnique(); }); // ── Giving ─────────────────────────────────────────────────────────── builder.Entity(entity => { entity.Property(e => e.Amount).HasColumnType("decimal(18,2)"); entity.Property(e => e.PaymentMethod).HasMaxLength(20).IsRequired(); entity.Property(e => e.CheckNumber).HasMaxLength(50); entity.Property(e => e.ZelleReferenceCode).HasMaxLength(100); entity.Property(e => e.PayPalTransactionId).HasMaxLength(100); entity.Property(e => e.Notes).HasMaxLength(500); entity.Property(e => e.CreatedBy).HasMaxLength(450); entity.Property(e => e.UpdatedBy).HasMaxLength(450); entity.HasIndex(e => new { e.MemberId, e.GivingDate }); entity.HasIndex(e => e.OfferingSessionId).HasFilter("\"OfferingSessionId\" IS NOT NULL"); entity.HasIndex(e => e.GivingDate); entity.HasOne(e => e.GivingCategory).WithMany() .HasForeignKey(e => e.GivingCategoryId).OnDelete(DeleteBehavior.Restrict); entity.HasOne(e => e.Member).WithMany() .HasForeignKey(e => e.MemberId).OnDelete(DeleteBehavior.SetNull); entity.HasOne(e => e.OfferingSession).WithMany(s => s.Givings) .HasForeignKey(e => e.OfferingSessionId).OnDelete(DeleteBehavior.Cascade); }); } }