using Microsoft.EntityFrameworkCore;
namespace AgriculturalPlatform.Api.Data;
///
/// 兼容已存在的数据库:EnsureCreated 不会为已存在的表补列,
/// 这里通过 information_schema 检测后逐列执行 ALTER TABLE,
/// 为 Farmers 表补充四级行政区划等新列(兼容 MySQL 5.7 / 8.0 各版本)。
///
public static class SchemaMigrator
{
public static async Task EnsureColumnsAsync(AppDbContext db)
{
var existing = new HashSet(
await db.Database
.SqlQuery($"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,'')");
}
///
/// 确保 Regions(行政区划)表存在。
/// 表结构与 scripts/areacity/import-regions.mjs 导入脚本一致;
/// 数据由该脚本导入(全国省市区乡镇四级,约 4.2 万条)。
///
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(
$"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);
}
}