using Microsoft.EntityFrameworkCore;
using Rmsys.Domain.Entities;
namespace Rmsys.Infrastructure;
///
/// 系统数据库上下文。
/// 约定(针对 MySQL 5.7 共享服务器):
/// · 表名一律小写(服务端 lower_case_table_names=1)
/// · 字符集 utf8mb4 / utf8mb4_general_ci(服务端默认是 latin1,必须显式覆盖)
/// · 金额/时长等不使用 decimal/date 特有能力,保持 5.7 兼容
///
public class RmsysDbContext : DbContext
{
public RmsysDbContext(DbContextOptions options) : base(options) { }
public DbSet Depts => Set();
public DbSet Meetings => Set();
public DbSet Cadres => Set();
public DbSet CadreResumes => Set();
public DbSet CadreFamilies => Set();
public DbSet CadreNotes => Set();
public DbSet CadreRelations => Set();
public DbSet MeetingCadres => Set();
public DbSet Materials => Set();
public DbSet AppointDocs => Set();
public DbSet AppointDocCadres => Set();
public DbSet DataPackages => Set();
public DbSet PackageItems => Set();
public DbSet PackageDevices => Set();
public DbSet PadDevices => Set();
public DbSet SysUsers => Set();
public DbSet SysRoles => Set();
public DbSet SysUserRoles => Set();
public DbSet PwdHistories => Set();
public DbSet AuditLogs => Set();
public DbSet DictItems => Set();
public DbSet SysConfigs => Set();
public DbSet ReadReceipts => Set();
protected override void OnModelCreating(ModelBuilder b)
{
// ---------- 全局:表名小写 ----------
foreach (var e in b.Model.GetEntityTypes())
{
var t = e.GetTableName();
if (t != null) e.SetTableName(t.ToLowerInvariant());
}
b.Entity(e =>
{
e.Property(x => x.Code).HasMaxLength(32).IsRequired();
e.Property(x => x.Name).HasMaxLength(64).IsRequired();
e.Property(x => x.Duty).HasMaxLength(255);
e.Property(x => x.Leader).HasMaxLength(32);
e.HasIndex(x => x.Code).IsUnique();
});
b.Entity(e =>
{
e.Property(x => x.Type).HasMaxLength(16).IsRequired();
e.Property(x => x.Name).HasMaxLength(128).IsRequired();
e.Property(x => x.Place).HasMaxLength(128);
e.Property(x => x.Host).HasMaxLength(32);
e.Property(x => x.Secret).HasMaxLength(16);
e.Property(x => x.SecretStars).HasMaxLength(8);
e.Property(x => x.PwdLevel).HasMaxLength(16);
e.Property(x => x.Status).HasMaxLength(16);
e.Property(x => x.Remark).HasMaxLength(500);
e.Property(x => x.BatchNo).HasMaxLength(32);
e.HasIndex(x => new { x.Type, x.SessionNo });
e.HasIndex(x => x.BatchNo);
});
b.Entity(e =>
{
e.Property(x => x.Name).HasMaxLength(32).IsRequired();
e.Property(x => x.Sex).HasMaxLength(4);
e.Property(x => x.Birth).HasMaxLength(16);
e.Property(x => x.Nation).HasMaxLength(16);
e.Property(x => x.NativePlace).HasMaxLength(64);
e.Property(x => x.BirthPlace).HasMaxLength(64);
e.Property(x => x.PartyDate).HasMaxLength(16);
e.Property(x => x.WorkDate).HasMaxLength(16);
e.Property(x => x.Health).HasMaxLength(32);
e.Property(x => x.TechPost).HasMaxLength(64);
e.Property(x => x.Expertise).HasMaxLength(255);
e.Property(x => x.EduFullSchool).HasMaxLength(128);
e.Property(x => x.EduFullMajor).HasMaxLength(128);
e.Property(x => x.EduFullLevel).HasMaxLength(32);
e.Property(x => x.EduFullDegree).HasMaxLength(32);
e.Property(x => x.EduInSchool).HasMaxLength(128);
e.Property(x => x.EduInMajor).HasMaxLength(128);
e.Property(x => x.EduInLevel).HasMaxLength(32);
e.Property(x => x.EduInDegree).HasMaxLength(32);
e.Property(x => x.CurrentPost).HasMaxLength(255);
e.Property(x => x.ProposedPost).HasMaxLength(255);
e.Property(x => x.DismissPost).HasMaxLength(255);
e.Property(x => x.Rewards).HasMaxLength(1000);
e.Property(x => x.Exams).HasMaxLength(255);
e.Property(x => x.AppointReason).HasMaxLength(1000);
e.Property(x => x.Kw).HasMaxLength(255);
e.Property(x => x.Perf).HasMaxLength(2000);
e.Property(x => x.Care).HasMaxLength(2000);
e.Property(x => x.Suggest).HasMaxLength(1000);
e.Property(x => x.PhotoPath).HasMaxLength(255);
e.HasIndex(x => new { x.DeptId, x.Name });
e.HasOne().WithMany().HasForeignKey(x => x.DeptId).OnDelete(DeleteBehavior.SetNull);
});
b.Entity(e =>
{
e.Property(x => x.Period).HasMaxLength(64);
e.Property(x => x.Content).HasMaxLength(500).IsRequired();
e.HasIndex(x => new { x.CadreId, x.Sort });
e.HasOne(x => x.Cadre).WithMany(x => x.Resumes).HasForeignKey(x => x.CadreId).OnDelete(DeleteBehavior.Cascade);
});
b.Entity(e =>
{
e.Property(x => x.Relation).HasMaxLength(16);
e.Property(x => x.Name).HasMaxLength(32);
e.Property(x => x.Age).HasMaxLength(8);
e.Property(x => x.Political).HasMaxLength(16);
e.Property(x => x.WorkUnit).HasMaxLength(255);
e.HasIndex(x => new { x.CadreId, x.Sort });
e.HasOne(x => x.Cadre).WithMany(x => x.Families).HasForeignKey(x => x.CadreId).OnDelete(DeleteBehavior.Cascade);
});
b.Entity(e =>
{
e.Property(x => x.FieldName).HasMaxLength(64);
e.Property(x => x.Content).HasMaxLength(1000).IsRequired();
e.Property(x => x.Source).HasMaxLength(16);
e.Property(x => x.Author).HasMaxLength(32);
e.HasIndex(x => new { x.CadreId, x.MeetingId });
e.HasOne(x => x.Cadre).WithMany(x => x.Notes).HasForeignKey(x => x.CadreId).OnDelete(DeleteBehavior.Cascade);
});
b.Entity(e =>
{
e.Property(x => x.RelatedName).HasMaxLength(32);
e.Property(x => x.Relation).HasMaxLength(16);
e.Property(x => x.RelatedPost).HasMaxLength(255);
e.HasIndex(x => x.CadreId);
});
b.Entity(e =>
{
e.Property(x => x.IssueNo).HasMaxLength(32);
e.Property(x => x.Result).HasMaxLength(16);
e.Property(x => x.Vote).HasMaxLength(16);
e.Property(x => x.Remark).HasMaxLength(500);
e.HasIndex(x => new { x.MeetingId, x.CadreId }).IsUnique();
e.HasIndex(x => new { x.MeetingId, x.SortNo });
e.HasOne(x => x.Meeting).WithMany(x => x.Cadres).HasForeignKey(x => x.MeetingId).OnDelete(DeleteBehavior.Cascade);
e.HasOne(x => x.Cadre).WithMany().HasForeignKey(x => x.CadreId).OnDelete(DeleteBehavior.Cascade);
});
b.Entity(e =>
{
e.Property(x => x.Type).HasMaxLength(16).IsRequired();
e.Property(x => x.Title).HasMaxLength(255);
e.Property(x => x.FileName).HasMaxLength(255);
e.Property(x => x.FilePath).HasMaxLength(500);
e.Property(x => x.Version).HasMaxLength(16);
e.Property(x => x.UploadedBy).HasMaxLength(32);
e.Property(x => x.Status).HasMaxLength(16);
// 唯一约束:同一会议同一干部的同一类材料只允许一行。
// 上传逻辑是「有则升版本、无则新增」,并发下两个请求会各自查到「无」而各插一行,
// 靠唯一索引兜住这种情况(代码里捕获冲突后改为更新)。
e.HasIndex(x => new { x.MeetingId, x.Type, x.CadreId }).IsUnique();
e.HasIndex(x => new { x.MeetingId, x.DeptId });
});
b.Entity(e =>
{
e.Property(x => x.DocNo).HasMaxLength(64);
e.Property(x => x.Title).HasMaxLength(255);
e.Property(x => x.FilePath).HasMaxLength(500);
e.Property(x => x.Version).HasMaxLength(16);
e.Property(x => x.UploadedBy).HasMaxLength(32);
e.Property(x => x.Status).HasMaxLength(16);
e.HasIndex(x => new { x.MeetingId, x.DeptId }).IsUnique();
});
b.Entity(e =>
{
e.Property(x => x.PkgNo).HasMaxLength(32).IsRequired();
e.Property(x => x.Encrypt).HasMaxLength(16);
e.Property(x => x.PwdHash).HasMaxLength(128);
e.Property(x => x.ClearPolicy).HasMaxLength(16);
e.Property(x => x.Watermark).HasMaxLength(128);
e.Property(x => x.FontLevel).HasMaxLength(8);
e.Property(x => x.SwitchesJson).HasMaxLength(1000);
e.Property(x => x.Status).HasMaxLength(16);
e.Property(x => x.FilePath).HasMaxLength(500);
e.Property(x => x.CreatedBy).HasMaxLength(32);
e.HasIndex(x => x.PkgNo).IsUnique();
e.HasIndex(x => x.MeetingId);
});
b.Entity(e =>
{
e.Property(x => x.MaterialType).HasMaxLength(16).IsRequired();
e.HasIndex(x => new { x.PackageId, x.MaterialType }).IsUnique();
});
b.Entity(e =>
{
e.HasIndex(x => new { x.PackageId, x.PadId }).IsUnique();
});
b.Entity(e =>
{
e.Property(x => x.PadNo).HasMaxLength(32).IsRequired();
e.Property(x => x.Model).HasMaxLength(64);
e.Property(x => x.OwnerLabel).HasMaxLength(32);
e.HasIndex(x => x.PadNo).IsUnique();
});
b.Entity(e =>
{
e.Property(x => x.Account).HasMaxLength(32).IsRequired();
e.Property(x => x.RealName).HasMaxLength(32).IsRequired();
e.Property(x => x.Phone).HasMaxLength(20);
e.Property(x => x.DataScope).HasMaxLength(32);
e.Property(x => x.PwdHash).HasMaxLength(128);
e.Property(x => x.PwdSalt).HasMaxLength(64);
e.HasIndex(x => x.Account).IsUnique();
});
b.Entity(e =>
{
e.Property(x => x.Code).HasMaxLength(32).IsRequired();
e.Property(x => x.Name).HasMaxLength(32).IsRequired();
e.Property(x => x.Perms).HasMaxLength(1000);
e.HasIndex(x => x.Code).IsUnique();
});
b.Entity(e =>
{
e.HasIndex(x => new { x.UserId, x.RoleId }).IsUnique();
});
b.Entity(e =>
{
e.Property(x => x.PwdHash).HasMaxLength(128).IsRequired();
e.HasIndex(x => new { x.UserId, x.ChangedAt });
});
b.Entity(e =>
{
e.Property(x => x.UserName).HasMaxLength(32);
e.Property(x => x.Role).HasMaxLength(32);
e.Property(x => x.Action).HasMaxLength(32).IsRequired();
e.Property(x => x.Target).HasMaxLength(255);
e.Property(x => x.Detail).HasMaxLength(1000);
e.Property(x => x.Ip).HasMaxLength(64);
e.Property(x => x.Device).HasMaxLength(32);
e.HasIndex(x => x.At);
e.HasIndex(x => new { x.Action, x.At });
e.HasIndex(x => new { x.UserName, x.At });
});
b.Entity(e =>
{
e.Property(x => x.Type).HasMaxLength(32).IsRequired();
e.Property(x => x.Code).HasMaxLength(32).IsRequired();
e.Property(x => x.Label).HasMaxLength(64).IsRequired();
e.HasIndex(x => new { x.Type, x.Code }).IsUnique();
});
b.Entity(e =>
{
e.Property(x => x.ConfigKey).HasMaxLength(64).IsRequired();
e.Property(x => x.ConfigValue).HasMaxLength(512);
e.Property(x => x.Remark).HasMaxLength(200);
e.Property(x => x.UpdatedBy).HasMaxLength(32);
e.HasIndex(x => x.ConfigKey).IsUnique();
});
b.Entity(e =>
{
e.Property(x => x.MaterialType).HasMaxLength(16).IsRequired();
e.Property(x => x.PadNo).HasMaxLength(32).IsRequired();
e.Property(x => x.ImportedBy).HasMaxLength(32);
// 同一会议同一干部的同一类材料、同一台设备只记一条(重复导入不翻倍)
e.HasIndex(x => new { x.MeetingId, x.CadreId, x.MaterialType, x.PadNo }).IsUnique();
e.HasIndex(x => x.MeetingId);
});
}
/// MySQL 5.7 需要显式 utf8mb4_general_ci(服务端默认 latin1)
public static void ApplyMySqlConventions(ModelBuilder b)
{
foreach (var e in b.Model.GetEntityTypes())
{
var t = e.GetTableName();
if (t != null) e.SetTableName(t.ToLowerInvariant());
}
}
}