using AgriculturalPlatform.Api.Models; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace AgriculturalPlatform.Api.Data; public class AppDbContext(DbContextOptions options) : DbContext(options) { public DbSet Users => Set(); public DbSet Organizations => Set(); public DbSet Farmers => Set(); public DbSet Regions => Set(); public DbSet Products => Set(); public DbSet PurchaseOrders => Set(); public DbSet PaymentRecords => Set(); public DbSet Invoices => Set(); 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() .Property(u => u.Username).HasMaxLength(50); modelBuilder.Entity() .HasIndex(u => u.Username).IsUnique(); modelBuilder.Entity() .HasOne(u => u.Org).WithMany().HasForeignKey(u => u.OrgId) .OnDelete(DeleteBehavior.SetNull); // 组织 modelBuilder.Entity() .Property(o => o.Type).HasMaxLength(32); modelBuilder.Entity() .Property(o => o.Name).HasMaxLength(200); modelBuilder.Entity() .HasIndex(o => new { o.Type, o.Name }); modelBuilder.Entity() .HasOne(o => o.Parent).WithMany().HasForeignKey(o => o.ParentId) .OnDelete(DeleteBehavior.Restrict); // 农户:身份证唯一 modelBuilder.Entity() .Property(f => f.IdCard).HasMaxLength(18); modelBuilder.Entity() .HasIndex(f => f.IdCard).IsUnique(); modelBuilder.Entity() .Property(f => f.Phone).HasMaxLength(20); modelBuilder.Entity() .HasIndex(f => f.Phone); modelBuilder.Entity() .Property(f => f.FarmerType).HasMaxLength(20); modelBuilder.Entity() .Property(f => f.IdCardFrontUrl).HasMaxLength(500); modelBuilder.Entity() .Property(f => f.IdCardBackUrl).HasMaxLength(500); modelBuilder.Entity() .Property(f => f.Province).HasMaxLength(50); modelBuilder.Entity() .Property(f => f.County).HasMaxLength(50); modelBuilder.Entity() .Property(f => f.Township).HasMaxLength(50); modelBuilder.Entity() .Property(f => f.Village).HasMaxLength(100); modelBuilder.Entity() .Property(f => f.GroupName).HasMaxLength(50); modelBuilder.Entity() .HasIndex(f => new { f.Province, f.County, f.Township }); // 行政区划(AreaCity 全国数据,表由导入脚本/启动建表创建) modelBuilder.Entity() .HasKey(r => r.Id); modelBuilder.Entity() .Property(r => r.Name).HasMaxLength(100); modelBuilder.Entity() .Property(r => r.ExtName).HasMaxLength(100); modelBuilder.Entity() .HasIndex(r => r.Pid); modelBuilder.Entity() .HasIndex(r => r.Deep); // 品种 modelBuilder.Entity() .Property(p => p.Name).HasMaxLength(100); modelBuilder.Entity() .HasIndex(p => p.Name).IsUnique(); // 收购单 modelBuilder.Entity() .Property(p => p.OrderNo).HasMaxLength(32); modelBuilder.Entity() .HasIndex(p => p.OrderNo).IsUnique(); modelBuilder.Entity() .HasIndex(p => new { p.Status, p.CreatedAt }); modelBuilder.Entity() .HasOne(p => p.Farmer).WithMany().HasForeignKey(p => p.FarmerId) .OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity() .HasOne(p => p.Product).WithMany().HasForeignKey(p => p.ProductId) .OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity() .HasOne(p => p.PurchaserOrg).WithMany().HasForeignKey(p => p.PurchaserOrgId) .OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity() .HasOne(p => p.Operator).WithMany().HasForeignKey(p => p.OperatorId) .OnDelete(DeleteBehavior.SetNull); // 支付 modelBuilder.Entity() .Property(p => p.PayNo).HasMaxLength(32); modelBuilder.Entity() .HasIndex(p => p.PayNo).IsUnique(); modelBuilder.Entity() .HasIndex(p => new { p.Status, p.CreatedAt }); modelBuilder.Entity() .HasOne(p => p.Farmer).WithMany().HasForeignKey(p => p.FarmerId) .OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity() .HasOne(p => p.PurchaseOrder).WithMany().HasForeignKey(p => p.PurchaseOrderId) .OnDelete(DeleteBehavior.SetNull); modelBuilder.Entity() .HasOne(p => p.PurchaserOrg).WithMany().HasForeignKey(p => p.PurchaserOrgId) .OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity() .HasOne(p => p.Operator).WithMany().HasForeignKey(p => p.OperatorId) .OnDelete(DeleteBehavior.SetNull); // 发票 modelBuilder.Entity() .Property(i => i.InvoiceNo).HasMaxLength(32); modelBuilder.Entity() .HasIndex(i => i.InvoiceNo).IsUnique(); modelBuilder.Entity() .Property(i => i.BatchNo).HasMaxLength(32); modelBuilder.Entity() .HasIndex(i => i.BatchNo); modelBuilder.Entity() .HasIndex(i => new { i.Status, i.IssueDate }); modelBuilder.Entity() .HasOne(i => i.Farmer).WithMany().HasForeignKey(i => i.FarmerId) .OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity() .HasOne(i => i.PurchaserOrg).WithMany().HasForeignKey(i => i.PurchaserOrgId) .OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity() .HasOne(i => i.Product).WithMany().HasForeignKey(i => i.ProductId) .OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity() .HasOne(i => i.PurchaseOrder).WithMany().HasForeignKey(i => i.PurchaseOrderId) .OnDelete(DeleteBehavior.SetNull); modelBuilder.Entity() .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); } } } } }