b3eb9d297a
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
177 lines
9.9 KiB
C#
177 lines
9.9 KiB
C#
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using ROLAC.API.Entities;
|
|
|
|
namespace ROLAC.API.Data;
|
|
|
|
public class AppDbContext : IdentityDbContext<AppUser, AppRole, string>
|
|
{
|
|
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
|
|
|
|
public DbSet<RefreshToken> RefreshTokens => Set<RefreshToken>();
|
|
public DbSet<Member> Members => Set<Member>();
|
|
public DbSet<FamilyUnit> FamilyUnits => Set<FamilyUnit>();
|
|
public DbSet<GivingCategory> GivingCategories => Set<GivingCategory>();
|
|
public DbSet<OfferingSession> OfferingSessions => Set<OfferingSession>();
|
|
public DbSet<Giving> Givings => Set<Giving>();
|
|
public DbSet<Ministry> Ministries => Set<Ministry>();
|
|
public DbSet<ExpenseCategoryGroup> ExpenseCategoryGroups => Set<ExpenseCategoryGroup>();
|
|
public DbSet<ExpenseSubCategory> ExpenseSubCategories => Set<ExpenseSubCategory>();
|
|
|
|
protected override void OnModelCreating(ModelBuilder builder)
|
|
{
|
|
base.OnModelCreating(builder);
|
|
|
|
// ── RefreshToken (unchanged) ────────────────────────────────────────
|
|
builder.Entity<RefreshToken>(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<AppUser>(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<AppRole>(entity =>
|
|
{
|
|
entity.Property(e => e.Description).HasMaxLength(500);
|
|
});
|
|
|
|
// ── FamilyUnit ──────────────────────────────────────────────────────
|
|
builder.Entity<FamilyUnit>(entity =>
|
|
{
|
|
entity.Property(e => e.FamilyName_en).HasMaxLength(200);
|
|
entity.Property(e => e.FamilyName_zh).HasMaxLength(200);
|
|
});
|
|
|
|
// ── Member ──────────────────────────────────────────────────────────
|
|
builder.Entity<Member>(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<GivingCategory>(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<OfferingSession>(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<Giving>(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);
|
|
});
|
|
|
|
// ── Ministry ─────────────────────────────────────────────────────────
|
|
builder.Entity<Ministry>(entity =>
|
|
{
|
|
entity.Property(e => e.Name_en).HasMaxLength(200).IsRequired();
|
|
entity.Property(e => e.Name_zh).HasMaxLength(200);
|
|
});
|
|
|
|
// ── ExpenseCategoryGroup ─────────────────────────────────────────────
|
|
builder.Entity<ExpenseCategoryGroup>(entity =>
|
|
{
|
|
entity.Property(e => e.Name_en).HasMaxLength(200).IsRequired();
|
|
entity.Property(e => e.Name_zh).HasMaxLength(200);
|
|
entity.Property(e => e.CreatedBy).HasMaxLength(450);
|
|
entity.Property(e => e.UpdatedBy).HasMaxLength(450);
|
|
});
|
|
|
|
// ── ExpenseSubCategory ───────────────────────────────────────────────
|
|
builder.Entity<ExpenseSubCategory>(entity =>
|
|
{
|
|
entity.Property(e => e.Name_en).HasMaxLength(200).IsRequired();
|
|
entity.Property(e => e.Name_zh).HasMaxLength(200);
|
|
entity.Property(e => e.CreatedBy).HasMaxLength(450);
|
|
entity.Property(e => e.UpdatedBy).HasMaxLength(450);
|
|
entity.HasOne(e => e.Group).WithMany(g => g.SubCategories)
|
|
.HasForeignKey(e => e.GroupId).OnDelete(DeleteBehavior.Restrict);
|
|
});
|
|
}
|
|
}
|