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()); } } }