263 lines
12 KiB
C#
263 lines
12 KiB
C#
using AgriculturalPlatform.Api.Models;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||
|
||
namespace AgriculturalPlatform.Api.Data;
|
||
|
||
public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
|
||
{
|
||
public DbSet<User> Users => Set<User>();
|
||
public DbSet<Organization> Organizations => Set<Organization>();
|
||
public DbSet<Farmer> Farmers => Set<Farmer>();
|
||
public DbSet<Region> Regions => Set<Region>();
|
||
public DbSet<Product> Products => Set<Product>();
|
||
public DbSet<PurchaseOrder> PurchaseOrders => Set<PurchaseOrder>();
|
||
public DbSet<PurchaseWeigh> PurchaseWeighs => Set<PurchaseWeigh>();
|
||
public DbSet<PurchaseTransfer> PurchaseTransfers => Set<PurchaseTransfer>();
|
||
public DbSet<PaymentRecord> PaymentRecords => Set<PaymentRecord>();
|
||
public DbSet<Invoice> Invoices => Set<Invoice>();
|
||
|
||
// 系统管理(RBAC)
|
||
public DbSet<SysDict> SysDicts => Set<SysDict>();
|
||
public DbSet<SysDictItem> SysDictItems => Set<SysDictItem>();
|
||
public DbSet<SysMenu> SysMenus => Set<SysMenu>();
|
||
public DbSet<SysRole> SysRoles => Set<SysRole>();
|
||
public DbSet<SysRoleMenu> SysRoleMenus => Set<SysRoleMenu>();
|
||
|
||
// 通知公告
|
||
public DbSet<Announcement> Announcements => Set<Announcement>();
|
||
public DbSet<AnnouncementRead> AnnouncementReads => Set<AnnouncementRead>();
|
||
|
||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||
{
|
||
base.OnModelCreating(modelBuilder);
|
||
|
||
// 所有枚举属性以字符串形式存储,便于阅读
|
||
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
|
||
{
|
||
foreach (var property in entityType.GetProperties())
|
||
{
|
||
if (property.ClrType.IsEnum)
|
||
{
|
||
var converterType = typeof(EnumToStringConverter<>).MakeGenericType(property.ClrType);
|
||
var converter = (ValueConverter)Activator.CreateInstance(converterType)!;
|
||
property.SetValueConverter(converter);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 用户
|
||
modelBuilder.Entity<User>()
|
||
.Property(u => u.Username).HasMaxLength(50);
|
||
modelBuilder.Entity<User>()
|
||
.HasIndex(u => u.Username).IsUnique();
|
||
modelBuilder.Entity<User>()
|
||
.HasOne(u => u.Org).WithMany().HasForeignKey(u => u.OrgId)
|
||
.OnDelete(DeleteBehavior.SetNull);
|
||
modelBuilder.Entity<User>()
|
||
.HasOne(u => u.SysRole).WithMany().HasForeignKey(u => u.RoleId)
|
||
.OnDelete(DeleteBehavior.SetNull);
|
||
|
||
// 组织
|
||
modelBuilder.Entity<Organization>()
|
||
.Property(o => o.Type).HasMaxLength(32);
|
||
modelBuilder.Entity<Organization>()
|
||
.Property(o => o.Name).HasMaxLength(200);
|
||
modelBuilder.Entity<Organization>()
|
||
.HasIndex(o => new { o.Type, o.Name });
|
||
modelBuilder.Entity<Organization>()
|
||
.HasOne(o => o.Parent).WithMany().HasForeignKey(o => o.ParentId)
|
||
.OnDelete(DeleteBehavior.Restrict);
|
||
|
||
// 农户:身份证唯一
|
||
modelBuilder.Entity<Farmer>()
|
||
.Property(f => f.IdCard).HasMaxLength(18);
|
||
modelBuilder.Entity<Farmer>()
|
||
.HasIndex(f => f.IdCard).IsUnique();
|
||
modelBuilder.Entity<Farmer>()
|
||
.Property(f => f.Phone).HasMaxLength(20);
|
||
modelBuilder.Entity<Farmer>()
|
||
.HasIndex(f => f.Phone);
|
||
modelBuilder.Entity<Farmer>()
|
||
.Property(f => f.FarmerType).HasMaxLength(20);
|
||
modelBuilder.Entity<Farmer>()
|
||
.Property(f => f.IdCardFrontUrl).HasMaxLength(500);
|
||
modelBuilder.Entity<Farmer>()
|
||
.Property(f => f.IdCardBackUrl).HasMaxLength(500);
|
||
modelBuilder.Entity<Farmer>()
|
||
.Property(f => f.Province).HasMaxLength(50);
|
||
modelBuilder.Entity<Farmer>()
|
||
.Property(f => f.County).HasMaxLength(50);
|
||
modelBuilder.Entity<Farmer>()
|
||
.Property(f => f.Township).HasMaxLength(50);
|
||
modelBuilder.Entity<Farmer>()
|
||
.Property(f => f.Village).HasMaxLength(100);
|
||
modelBuilder.Entity<Farmer>()
|
||
.Property(f => f.GroupName).HasMaxLength(50);
|
||
modelBuilder.Entity<Farmer>()
|
||
.HasIndex(f => new { f.Province, f.County, f.Township });
|
||
|
||
// 行政区划(AreaCity 全国数据,表由导入脚本/启动建表创建)
|
||
modelBuilder.Entity<Region>()
|
||
.HasKey(r => r.Id);
|
||
modelBuilder.Entity<Region>()
|
||
.Property(r => r.Name).HasMaxLength(100);
|
||
modelBuilder.Entity<Region>()
|
||
.Property(r => r.ExtName).HasMaxLength(100);
|
||
modelBuilder.Entity<Region>()
|
||
.HasIndex(r => r.Pid);
|
||
modelBuilder.Entity<Region>()
|
||
.HasIndex(r => r.Deep);
|
||
|
||
// 品种
|
||
modelBuilder.Entity<Product>()
|
||
.Property(p => p.Name).HasMaxLength(100);
|
||
modelBuilder.Entity<Product>()
|
||
.HasIndex(p => p.Name).IsUnique();
|
||
|
||
// 收购单
|
||
modelBuilder.Entity<PurchaseOrder>()
|
||
.Property(p => p.OrderNo).HasMaxLength(32);
|
||
modelBuilder.Entity<PurchaseOrder>()
|
||
.HasIndex(p => p.OrderNo).IsUnique();
|
||
modelBuilder.Entity<PurchaseOrder>()
|
||
.HasIndex(p => new { p.Status, p.CreatedAt });
|
||
modelBuilder.Entity<PurchaseOrder>()
|
||
.HasOne(p => p.Farmer).WithMany().HasForeignKey(p => p.FarmerId)
|
||
.OnDelete(DeleteBehavior.Restrict);
|
||
modelBuilder.Entity<PurchaseOrder>()
|
||
.HasOne(p => p.Product).WithMany().HasForeignKey(p => p.ProductId)
|
||
.OnDelete(DeleteBehavior.Restrict);
|
||
modelBuilder.Entity<PurchaseOrder>()
|
||
.HasOne(p => p.PurchaserOrg).WithMany().HasForeignKey(p => p.PurchaserOrgId)
|
||
.OnDelete(DeleteBehavior.Restrict);
|
||
modelBuilder.Entity<PurchaseOrder>()
|
||
.HasOne(p => p.Operator).WithMany().HasForeignKey(p => p.OperatorId)
|
||
.OnDelete(DeleteBehavior.SetNull);
|
||
|
||
// 收购单-磅次
|
||
modelBuilder.Entity<PurchaseWeigh>()
|
||
.HasOne(w => w.PurchaseOrder).WithMany(p => p.Weighs)
|
||
.HasForeignKey(w => w.PurchaseOrderId)
|
||
.OnDelete(DeleteBehavior.Cascade);
|
||
|
||
// 票据过户
|
||
modelBuilder.Entity<PurchaseTransfer>()
|
||
.HasOne(t => t.PurchaseOrder).WithMany(p => p.Transfers)
|
||
.HasForeignKey(t => t.PurchaseOrderId)
|
||
.OnDelete(DeleteBehavior.Cascade);
|
||
modelBuilder.Entity<PurchaseTransfer>()
|
||
.HasOne(t => t.Operator).WithMany().HasForeignKey(t => t.OperatorId)
|
||
.OnDelete(DeleteBehavior.SetNull);
|
||
|
||
// 数据字典
|
||
modelBuilder.Entity<SysDict>()
|
||
.Property(d => d.Code).HasMaxLength(64);
|
||
modelBuilder.Entity<SysDict>()
|
||
.HasIndex(d => d.Code).IsUnique();
|
||
modelBuilder.Entity<SysDict>()
|
||
.Property(d => d.Name).HasMaxLength(100);
|
||
modelBuilder.Entity<SysDictItem>()
|
||
.Property(i => i.Label).HasMaxLength(100);
|
||
modelBuilder.Entity<SysDictItem>()
|
||
.Property(i => i.Value).HasMaxLength(64);
|
||
modelBuilder.Entity<SysDictItem>()
|
||
.HasIndex(i => new { i.DictId, i.Value }).IsUnique();
|
||
modelBuilder.Entity<SysDict>()
|
||
.HasMany(d => d.Items).WithOne().HasForeignKey(i => i.DictId)
|
||
.OnDelete(DeleteBehavior.Cascade);
|
||
|
||
// 菜单(自引用父子关系显式指定外键,避免 EF 推断额外列)
|
||
modelBuilder.Entity<SysMenu>()
|
||
.Property(m => m.Name).HasMaxLength(100);
|
||
modelBuilder.Entity<SysMenu>()
|
||
.Property(m => m.Path).HasMaxLength(200);
|
||
modelBuilder.Entity<SysMenu>()
|
||
.Property(m => m.Permission).HasMaxLength(100);
|
||
modelBuilder.Entity<SysMenu>()
|
||
.HasIndex(m => m.Permission);
|
||
modelBuilder.Entity<SysMenu>()
|
||
.HasMany(m => m.Children).WithOne().HasForeignKey(m => m.ParentId)
|
||
.OnDelete(DeleteBehavior.Restrict);
|
||
|
||
// 角色
|
||
modelBuilder.Entity<SysRole>()
|
||
.Property(r => r.Name).HasMaxLength(100);
|
||
modelBuilder.Entity<SysRole>()
|
||
.HasIndex(r => r.Code).IsUnique();
|
||
modelBuilder.Entity<SysRoleMenu>()
|
||
.HasKey(rm => new { rm.RoleId, rm.MenuId });
|
||
|
||
// 公告
|
||
modelBuilder.Entity<Announcement>()
|
||
.Property(a => a.Title).HasMaxLength(200);
|
||
modelBuilder.Entity<Announcement>()
|
||
.HasIndex(a => new { a.Type, a.PublishedAt });
|
||
modelBuilder.Entity<Announcement>()
|
||
.HasOne(a => a.Publisher).WithMany().HasForeignKey(a => a.PublisherId)
|
||
.OnDelete(DeleteBehavior.SetNull);
|
||
modelBuilder.Entity<AnnouncementRead>()
|
||
.HasIndex(r => new { r.AnnouncementId, r.UserId }).IsUnique();
|
||
|
||
// 支付
|
||
modelBuilder.Entity<PaymentRecord>()
|
||
.Property(p => p.PayNo).HasMaxLength(32);
|
||
modelBuilder.Entity<PaymentRecord>()
|
||
.HasIndex(p => p.PayNo).IsUnique();
|
||
modelBuilder.Entity<PaymentRecord>()
|
||
.HasIndex(p => new { p.Status, p.CreatedAt });
|
||
modelBuilder.Entity<PaymentRecord>()
|
||
.HasOne(p => p.Farmer).WithMany().HasForeignKey(p => p.FarmerId)
|
||
.OnDelete(DeleteBehavior.Restrict);
|
||
modelBuilder.Entity<PaymentRecord>()
|
||
.HasOne(p => p.PurchaseOrder).WithMany().HasForeignKey(p => p.PurchaseOrderId)
|
||
.OnDelete(DeleteBehavior.SetNull);
|
||
modelBuilder.Entity<PaymentRecord>()
|
||
.HasOne(p => p.PurchaserOrg).WithMany().HasForeignKey(p => p.PurchaserOrgId)
|
||
.OnDelete(DeleteBehavior.Restrict);
|
||
modelBuilder.Entity<PaymentRecord>()
|
||
.HasOne(p => p.Operator).WithMany().HasForeignKey(p => p.OperatorId)
|
||
.OnDelete(DeleteBehavior.SetNull);
|
||
|
||
// 发票
|
||
modelBuilder.Entity<Invoice>()
|
||
.Property(i => i.InvoiceNo).HasMaxLength(32);
|
||
modelBuilder.Entity<Invoice>()
|
||
.HasIndex(i => i.InvoiceNo).IsUnique();
|
||
modelBuilder.Entity<Invoice>()
|
||
.Property(i => i.BatchNo).HasMaxLength(32);
|
||
modelBuilder.Entity<Invoice>()
|
||
.HasIndex(i => i.BatchNo);
|
||
modelBuilder.Entity<Invoice>()
|
||
.HasIndex(i => new { i.Status, i.IssueDate });
|
||
modelBuilder.Entity<Invoice>()
|
||
.HasOne(i => i.Farmer).WithMany().HasForeignKey(i => i.FarmerId)
|
||
.OnDelete(DeleteBehavior.Restrict);
|
||
modelBuilder.Entity<Invoice>()
|
||
.HasOne(i => i.PurchaserOrg).WithMany().HasForeignKey(i => i.PurchaserOrgId)
|
||
.OnDelete(DeleteBehavior.Restrict);
|
||
modelBuilder.Entity<Invoice>()
|
||
.HasOne(i => i.Product).WithMany().HasForeignKey(i => i.ProductId)
|
||
.OnDelete(DeleteBehavior.Restrict);
|
||
modelBuilder.Entity<Invoice>()
|
||
.HasOne(i => i.PurchaseOrder).WithMany().HasForeignKey(i => i.PurchaseOrderId)
|
||
.OnDelete(DeleteBehavior.SetNull);
|
||
modelBuilder.Entity<Invoice>()
|
||
.HasOne(i => i.Operator).WithMany().HasForeignKey(i => i.OperatorId)
|
||
.OnDelete(DeleteBehavior.SetNull);
|
||
|
||
// 金额/重量精度
|
||
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
|
||
{
|
||
foreach (var property in entityType.GetProperties())
|
||
{
|
||
if (property.ClrType == typeof(decimal) || property.ClrType == typeof(decimal?))
|
||
{
|
||
property.SetPrecision(18);
|
||
property.SetScale(2);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|