新增 SpaceBookingDbContext 類別及其配置

新增 `SpaceBookingDbContext` 類別,繼承自 `DbContext`,定義了 `Departments`、`Roles` 和 `Accounts` 資料集。實作模型配置方法以設定資料表名稱、主鍵、欄位屬性及外鍵關聯。覆寫 `SaveChanges` 和 `SaveChangesAsync` 方法,自動更新 `UpdatedAt` 欄位的時間戳記,確保 `CreatedAt` 在新增時不被修改。
This commit is contained in:
Chen, Chun-Yi 2025-09-30 10:41:04 +08:00
parent 1897e076c2
commit 2b8df04ece

View File

@ -0,0 +1,255 @@
using Microsoft.EntityFrameworkCore;
using Models.Entities;
using XisongSpaceBooking_BackEnd.Models.Entities;
namespace XisongSpaceBooking_BackEnd.Configurations
{
/// <summary>
/// 空間預約系統的資料庫內容類別
/// </summary>
public class SpaceBookingDbContext : DbContext
{
public SpaceBookingDbContext(DbContextOptions<SpaceBookingDbContext> options) : base(options)
{
}
/// <summary>
/// 處室資料集
/// </summary>
public DbSet<DepartmentEntity> Departments { get; set; }
/// <summary>
/// 身份資料集
/// </summary>
public DbSet<RoleEntity> Roles { get; set; }
/// <summary>
/// 帳號資料集
/// </summary>
public DbSet<AccountEntity> Accounts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// 配置 Department 實體
ConfigureDepartment(modelBuilder);
// 配置 Role 實體
ConfigureRole(modelBuilder);
// 配置 Account 實體
ConfigureAccount(modelBuilder);
}
/// <summary>
/// 配置 Department 實體
/// </summary>
/// <param name="modelBuilder">模型建構器</param>
private static void ConfigureDepartment(ModelBuilder modelBuilder)
{
var entity = modelBuilder.Entity<DepartmentEntity>();
// 設定資料表名稱
entity.ToTable("departments");
// 設定主鍵
entity.HasKey(d => d.DepartmentId);
entity.Property(d => d.DepartmentId)
.HasColumnName("department_id")
.ValueGeneratedOnAdd()
.HasComment("處室 ID");
// 設定處室名稱
entity.Property(d => d.DepartmentName)
.HasColumnName("department_name")
.HasMaxLength(20)
.IsRequired()
.HasComment("處室名稱");
}
/// <summary>
/// 配置 Role 實體
/// </summary>
/// <param name="modelBuilder">模型建構器</param>
private static void ConfigureRole(ModelBuilder modelBuilder)
{
var entity = modelBuilder.Entity<RoleEntity>();
// 設定資料表名稱
entity.ToTable("roles");
// 設定主鍵
entity.HasKey(r => r.RoleId);
entity.Property(r => r.RoleId)
.HasColumnName("role_id")
.ValueGeneratedOnAdd()
.HasComment("身份 ID");
// 設定身份名稱
entity.Property(r => r.RoleName)
.HasColumnName("role_name")
.HasMaxLength(20)
.IsRequired()
.HasComment("身份名稱");
}
/// <summary>
/// 配置 Account 實體
/// </summary>
/// <param name="modelBuilder">模型建構器</param>
private static void ConfigureAccount(ModelBuilder modelBuilder)
{
var entity = modelBuilder.Entity<AccountEntity>();
// 設定資料表名稱
entity.ToTable("accounts");
// 設定主鍵
entity.HasKey(a => a.AccountId);
entity.Property(a => a.AccountId)
.HasColumnName("account_id")
.ValueGeneratedOnAdd()
.HasComment("帳號 ID");
// 設定使用者姓名
entity.Property(a => a.Name)
.HasColumnName("name")
.HasMaxLength(20)
.IsRequired()
.HasComment("使用者姓名");
// 設定帳號名稱(唯一)
entity.Property(a => a.Username)
.HasColumnName("username")
.HasMaxLength(20)
.IsRequired()
.HasComment("帳號名稱");
// 設定密碼
entity.Property(a => a.Password)
.HasColumnName("password")
.HasMaxLength(255)
.IsRequired()
.HasComment("密碼(加密)");
// 設定電子郵件(唯一)
entity.Property(a => a.Email)
.HasColumnName("email")
.HasMaxLength(50)
.IsRequired()
.HasComment("電子郵件");
// 設定處室 ID外鍵
entity.Property(a => a.DepartmentId)
.HasColumnName("department_id")
.IsRequired()
.HasComment("處室 ID");
// 設定身份 ID外鍵
entity.Property(a => a.RoleId)
.HasColumnName("role_id")
.IsRequired()
.HasComment("身份 ID");
// 設定帳號狀態(轉換為字串儲存)
entity.Property(a => a.Status)
.HasColumnName("status")
.HasConversion(
v => v.ToString().ToLower(),
v => Enum.Parse<AccountStatus>(v, true))
.HasMaxLength(20)
.HasDefaultValue(AccountStatus.Unverified)
.IsRequired()
.HasComment("帳號狀態");
// 設定 BaseEntity 屬性
entity.Property(a => a.CreatedAt)
.HasColumnName("created_at")
.HasDefaultValueSql("CURRENT_TIMESTAMP")
.IsRequired()
.HasComment("建立時間");
entity.Property(a => a.UpdatedAt)
.HasColumnName("updated_at")
.ValueGeneratedOnUpdate()
.HasComment("更新時間");
entity.Property(a => a.ModifiedBy)
.HasColumnName("modified_by")
.IsRequired(false)
.HasComment("最後修改者帳號 ID");
// 設定唯一索引
entity.HasIndex(a => a.Username)
.IsUnique()
.HasDatabaseName("IX_accounts_username");
entity.HasIndex(a => a.Email)
.IsUnique()
.HasDatabaseName("IX_accounts_email");
// 設定外鍵關聯
entity.HasOne(a => a.Department)
.WithMany()
.HasForeignKey(a => a.DepartmentId)
.OnDelete(DeleteBehavior.Restrict)
.HasConstraintName("FK_accounts_departments");
entity.HasOne(a => a.Role)
.WithMany()
.HasForeignKey(a => a.RoleId)
.OnDelete(DeleteBehavior.Restrict)
.HasConstraintName("FK_accounts_roles");
// 設定自參考外鍵ModifiedBy
entity.HasOne<AccountEntity>()
.WithMany()
.HasForeignKey(a => a.ModifiedBy)
.OnDelete(DeleteBehavior.SetNull)
.HasConstraintName("FK_accounts_modified_by");
}
/// <summary>
/// 覆寫 SaveChanges 以自動更新 UpdatedAt 欄位
/// </summary>
public override int SaveChanges()
{
UpdateTimestamps();
return base.SaveChanges();
}
/// <summary>
/// 覆寫 SaveChangesAsync 以自動更新 UpdatedAt 欄位
/// </summary>
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
UpdateTimestamps();
return await base.SaveChangesAsync(cancellationToken);
}
/// <summary>
/// 更新時間戳記
/// </summary>
private void UpdateTimestamps()
{
var entries = ChangeTracker.Entries<BaseEntity>();
foreach (var entry in entries)
{
switch (entry.State)
{
case EntityState.Added:
entry.Entity.UpdatedAt = DateTime.UtcNow;
break;
case EntityState.Modified:
entry.Entity.UpdatedAt = DateTime.UtcNow;
// 確保 CreatedAt 不會被修改
entry.Property(e => e.CreatedAt).IsModified = false;
break;
}
}
}
}
}