Files
F8WebAI/backend/AgriculturalPlatform.Api/Data/AppDbContext.cs
T

263 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
}
}
}
}
}