完善基础数据
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using FreeSql;
|
||||
using F9WebAiTest.Domain.Entities.SYS.WuziMulus;
|
||||
using F9WebAiTest.Domain.Enums.SYS.Departments;
|
||||
using F9WebAiTest.Domain.Enums.SYS.WuziMulus;
|
||||
|
||||
namespace F9WebAiTest.Infrastructure.Data;
|
||||
|
||||
/// <summary>
|
||||
/// 物资数据导入:来源于 F9 系统 biz_base_wuzigroup(物资分组)与 biz_base_wuzimulu(物资目录)两张表的导出数据。
|
||||
/// 幂等:按原始 Id 判重,已存在则跳过。
|
||||
/// </summary>
|
||||
public static class WuziSeedData
|
||||
{
|
||||
private const string GroupResource = "F9WebAiTest.Infrastructure.Data.SeedData.biz_base_wuzigroup.json";
|
||||
private const string MuluResource = "F9WebAiTest.Infrastructure.Data.SeedData.biz_base_wuzimulu.json";
|
||||
|
||||
private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNameCaseInsensitive = true };
|
||||
|
||||
public static void Seed(IFreeSql fsql)
|
||||
{
|
||||
try
|
||||
{
|
||||
SeedGroups(fsql);
|
||||
SeedMulu(fsql);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[WuziSeed] 物资数据导入跳过:{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>导入物资分组</summary>
|
||||
private static void SeedGroups(IFreeSql fsql)
|
||||
{
|
||||
var items = Load<WuziGroupSeedItem>(GroupResource);
|
||||
if (items.Count == 0) return;
|
||||
|
||||
var existIds = fsql.Select<WuziGroup>().DisableGlobalFilter("软删除").ToList().Select(x => x.Id).ToHashSet();
|
||||
|
||||
var inserts = new List<WuziGroup>();
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item.Id <= 0 || existIds.Contains(item.Id)) continue;
|
||||
if (string.IsNullOrWhiteSpace(item.Name)) continue;
|
||||
|
||||
inserts.Add(new WuziGroup(item.Id, (WuziBusiness_Type_Enum)item.BusinessType,
|
||||
(Department_DutyType_Enum)item.DepartmentType, item.Code ?? string.Empty, item.Name.Trim(),
|
||||
item.ParentId, item.SortOrder, item.Description ?? string.Empty)
|
||||
{
|
||||
CreatedAt = ParseLegacyDate(item.CreatedAt) ?? DateTime.Now,
|
||||
CreatedBy = item.CreatedBy ?? string.Empty,
|
||||
UpdatedAt = ParseLegacyDate(item.UpdatedAt)
|
||||
});
|
||||
}
|
||||
|
||||
if (inserts.Count > 0) fsql.Insert(inserts).ExecuteAffrows();
|
||||
Console.WriteLine($"[WuziSeed] 物资分组:来源 {items.Count} 条,新增 {inserts.Count} 条");
|
||||
}
|
||||
|
||||
/// <summary>导入物资目录</summary>
|
||||
private static void SeedMulu(IFreeSql fsql)
|
||||
{
|
||||
var items = Load<WuziMuluSeedItem>(MuluResource);
|
||||
if (items.Count == 0) return;
|
||||
|
||||
var existIds = fsql.Select<WuziMulu>().DisableGlobalFilter("软删除").ToList().Select(x => x.Id).ToHashSet();
|
||||
|
||||
var inserts = new List<WuziMulu>();
|
||||
var orphan = 0;
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item.Id <= 0 || existIds.Contains(item.Id)) continue;
|
||||
if (string.IsNullOrWhiteSpace(item.Name)) continue;
|
||||
if (item.GroupId <= 0) { orphan++; continue; }
|
||||
|
||||
inserts.Add(new WuziMulu(item.Id, item.GroupId, item.Name.Trim(), item.Code ?? string.Empty,
|
||||
item.Unit ?? string.Empty, item.Guige ?? string.Empty, item.Xinghao ?? string.Empty,
|
||||
item.PinyinName ?? string.Empty, item.Kucunyujing, item.SortOrder, ParseBool(item.IsYujing), item.SaleRate)
|
||||
{
|
||||
CreatedAt = ParseLegacyDate(item.CreatedAt) ?? DateTime.Now,
|
||||
CreatedBy = item.CreatedBy ?? string.Empty,
|
||||
UpdatedAt = ParseLegacyDate(item.UpdatedAt)
|
||||
});
|
||||
}
|
||||
|
||||
// 分批插入(1000 条一次插入会超出 SQL 参数上限)
|
||||
foreach (var batch in inserts.Chunk(200)) fsql.Insert(batch.ToList()).ExecuteAffrows();
|
||||
Console.WriteLine($"[WuziSeed] 物资目录:来源 {items.Count} 条,新增 {inserts.Count} 条,跳过无分组 {orphan} 条");
|
||||
}
|
||||
|
||||
private static List<T> Load<T>(string resourceName)
|
||||
{
|
||||
var assembly = typeof(WuziSeedData).Assembly;
|
||||
using var stream = assembly.GetManifestResourceStream(resourceName);
|
||||
if (stream == null)
|
||||
{
|
||||
Console.WriteLine($"[WuziSeed] 未找到内嵌资源:{resourceName}");
|
||||
return new List<T>();
|
||||
}
|
||||
return JsonSerializer.Deserialize<List<T>>(stream, JsonOptions) ?? new List<T>();
|
||||
}
|
||||
|
||||
/// <summary>is_yujing 在导出数据里可能是 "0"/"1" 字符串、数字或布尔</summary>
|
||||
private static bool ParseBool(JsonElement element)
|
||||
{
|
||||
switch (element.ValueKind)
|
||||
{
|
||||
case JsonValueKind.String:
|
||||
var text = element.GetString();
|
||||
return text == "1" || string.Equals(text, "true", StringComparison.OrdinalIgnoreCase);
|
||||
case JsonValueKind.Number:
|
||||
return element.GetInt32() != 0;
|
||||
case JsonValueKind.True:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>解析 F9 导出的日期(形如 d/M/yyyy H:mm:ss.fff),1970 占位值视为未更新返回 null</summary>
|
||||
private static readonly string[] LegacyDateFormats =
|
||||
{
|
||||
"d/M/yyyy H:mm:ss.fff", "d/M/yyyy H:mm:ss", "d/M/yyyy H:mm",
|
||||
"M/d/yyyy H:mm:ss.fff", "M/d/yyyy H:mm:ss", "M/d/yyyy H:mm",
|
||||
"yyyy-MM-dd HH:mm:ss.fff", "yyyy-MM-dd HH:mm:ss"
|
||||
};
|
||||
|
||||
private static DateTime? ParseLegacyDate(string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value)) return null;
|
||||
|
||||
if (DateTime.TryParseExact(value, LegacyDateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out var exact))
|
||||
return exact.Year <= 1900 ? null : exact;
|
||||
|
||||
if (DateTime.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var any))
|
||||
return any.Year <= 1900 ? null : any;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private sealed class WuziGroupSeedItem
|
||||
{
|
||||
[JsonPropertyName("id")] public long Id { get; set; }
|
||||
[JsonPropertyName("created_by")] public string CreatedBy { get; set; }
|
||||
[JsonPropertyName("created_at")] public string CreatedAt { get; set; }
|
||||
[JsonPropertyName("updated_at")] public string UpdatedAt { get; set; }
|
||||
[JsonPropertyName("businesstype")] public int BusinessType { get; set; }
|
||||
[JsonPropertyName("departmenttype")] public int DepartmentType { get; set; }
|
||||
[JsonPropertyName("code")] public string Code { get; set; }
|
||||
[JsonPropertyName("name")] public string Name { get; set; }
|
||||
[JsonPropertyName("parentid")] public long ParentId { get; set; }
|
||||
[JsonPropertyName("sortorder")] public int SortOrder { get; set; }
|
||||
[JsonPropertyName("description")] public string Description { get; set; }
|
||||
}
|
||||
|
||||
private sealed class WuziMuluSeedItem
|
||||
{
|
||||
[JsonPropertyName("id")] public long Id { get; set; }
|
||||
[JsonPropertyName("created_by")] public string CreatedBy { get; set; }
|
||||
[JsonPropertyName("created_at")] public string CreatedAt { get; set; }
|
||||
[JsonPropertyName("updated_at")] public string UpdatedAt { get; set; }
|
||||
[JsonPropertyName("groupid")] public long GroupId { get; set; }
|
||||
[JsonPropertyName("name")] public string Name { get; set; }
|
||||
[JsonPropertyName("code")] public string Code { get; set; }
|
||||
[JsonPropertyName("unit")] public string Unit { get; set; }
|
||||
[JsonPropertyName("guige")] public string Guige { get; set; }
|
||||
[JsonPropertyName("xinghao")] public string Xinghao { get; set; }
|
||||
[JsonPropertyName("pinyinname")] public string PinyinName { get; set; }
|
||||
[JsonPropertyName("kucunyujing")] public decimal Kucunyujing { get; set; }
|
||||
[JsonPropertyName("sortorder")] public int SortOrder { get; set; }
|
||||
|
||||
/// <summary>F9 导出为字符串 "0"/"1"(兼容数字与布尔写法)</summary>
|
||||
[JsonPropertyName("is_yujing")] public JsonElement IsYujing { get; set; }
|
||||
|
||||
[JsonPropertyName("SaleRate")] public decimal SaleRate { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user