Files
F8WebAI/backend/AgriculturalPlatform.Api/Data/SchemaMigrator.cs
T
fanhongcai c377421a3e 新增农户功能升级:身份证OCR/OSS上传、头像采集、同名村检测、Region热度排序及表单体验优化
- Region 表新增热度列,热门省份优先显示
- 区县下拉按地级市分组、已录区县优先、支持全省搜索
- 组选择内置一组至二十组
- 银行卡号独立行+粗体预览,开户行独立行
- 新增农户类型:农户/个体户/合作社/经营集体/公司
- 身份证正反面支持高拍仪/摄像头OCR与手机扫码上传,附件存本地/OSS
- 新增农户头像采集组件(摄像头/本地上传),预留人脸识别收购扩展
- 同名村弹窗提醒(防选错乡镇)
- 编辑窗体禁止遮罩/Esc误关,整体加宽适配高频操作
- 修复二维码局域网手机无法访问(监听0.0.0.0、局域网IP识别、Vite代理兜底)
2026-08-13 16:07:35 +08:00

88 lines
4.2 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 Microsoft.EntityFrameworkCore;
namespace AgriculturalPlatform.Api.Data;
/// <summary>
/// 兼容已存在的数据库:EnsureCreated 不会为已存在的表补列,
/// 这里通过 information_schema 检测后逐列执行 ALTER TABLE
/// 为 Farmers 表补充四级行政区划等新列(兼容 MySQL 5.7 / 8.0 各版本)。
/// </summary>
public static class SchemaMigrator
{
public static async Task EnsureColumnsAsync(AppDbContext db)
{
var existing = new HashSet<string>(
await db.Database
.SqlQuery<string>($"SELECT COLUMN_NAME AS Value FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'Farmers'")
.ToListAsync(),
StringComparer.OrdinalIgnoreCase);
(string Name, string Ddl)[] columns =
[
("Province", "Province NVARCHAR(50) NULL"),
("County", "County NVARCHAR(50) NULL"),
("Township", "Township NVARCHAR(50) NULL"),
("GroupName", "GroupName NVARCHAR(50) NULL"),
("FarmerType", "FarmerType NVARCHAR(20) NULL"),
("IdCardFrontUrl", "IdCardFrontUrl NVARCHAR(500) NULL"),
("IdCardBackUrl", "IdCardBackUrl NVARCHAR(500) NULL"),
("AvatarUrl", "AvatarUrl NVARCHAR(500) NULL"),
];
foreach (var col in columns)
{
if (existing.Contains(col.Name)) continue;
await db.Database.ExecuteSqlRawAsync($"ALTER TABLE Farmers ADD COLUMN {col.Ddl}");
}
// 历史数据的新列为 NULL,EF 映射为不可空 string 读取会抛 DBNull 异常,统一刷新为空串(幂等)
await db.Database.ExecuteSqlRawAsync(
"UPDATE Farmers SET Province = COALESCE(Province,''), County = COALESCE(County,''), " +
"Township = COALESCE(Township,''), GroupName = COALESCE(GroupName,''), " +
"FarmerType = COALESCE(FarmerType,'农户'), " +
"IdCardFrontUrl = COALESCE(IdCardFrontUrl,''), IdCardBackUrl = COALESCE(IdCardBackUrl,''), " +
"AvatarUrl = COALESCE(AvatarUrl,'')");
}
/// <summary>
/// 确保 Regions(行政区划)表存在。
/// 表结构与 scripts/areacity/import-regions.mjs 导入脚本一致;
/// 数据由该脚本导入(全国省市区乡镇四级,约 4.2 万条)。
/// </summary>
public static async Task EnsureRegionsTableAsync(AppDbContext db)
{
await db.Database.ExecuteSqlRawAsync("""
CREATE TABLE IF NOT EXISTS Regions (
Id INT NOT NULL PRIMARY KEY,
Pid INT NOT NULL,
Deep INT NOT NULL,
Name VARCHAR(100) NOT NULL,
ExtName VARCHAR(100) NOT NULL,
Pinyin VARCHAR(200) NOT NULL DEFAULT '',
PinyinPrefix VARCHAR(10) NOT NULL DEFAULT '',
Hot INT NOT NULL DEFAULT 0,
KEY idx_regions_pid (Pid),
KEY idx_regions_deep (Deep)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
""");
// 老库补充 Hot 热度列(幂等)
var hotExists = await db.Database.SqlQuery<int>(
$"SELECT COUNT(*) AS Value FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'Regions' AND COLUMN_NAME = 'Hot'")
.FirstOrDefaultAsync();
if (hotExists == 0)
await db.Database.ExecuteSqlRawAsync("ALTER TABLE Regions ADD COLUMN Hot INT NOT NULL DEFAULT 0");
// 常用省份热度值(值越大越靠前,幂等可重复执行)
(string Name, int Hot)[] hotProvinces =
[
("四川省", 20), ("广西壮族自治区", 19), ("陕西省", 18), ("重庆市", 17), ("安徽省", 16),
("云南省", 15), ("贵州省", 14), ("河南省", 13), ("山东省", 12), ("湖北省", 11), ("湖南省", 10),
("甘肃省", 9), ("新疆维吾尔自治区", 8), ("江西省", 7), ("福建省", 6), ("广东省", 5),
("河北省", 4), ("山西省", 3), ("江苏省", 2), ("浙江省", 1),
];
foreach (var p in hotProvinces)
await db.Database.ExecuteSqlRawAsync(
"UPDATE Regions SET Hot = {0} WHERE Deep = 0 AND ExtName = {1}", p.Hot, p.Name);
}
}