using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using MiGu.DB.Abstractions.Runtime; using MiGu.DB.Domains.Wms; using MiGu.DB.Kernel.Context; namespace MiGu.DB.Domains.Migrators; // 启动期数据修补:Schema 初始化之后按 Order 执行,须幂等。 // 优先 LINQ / ExecuteUpdateAsync;枚举 converter 无法匹配旧字符串时允许定点 raw UPDATE(Sqlite)。 /// 将 simple_fields.other 回填到 car_type(替代原 PlatformPersistence raw UPDATE)。 public sealed class SimpleFieldsCarTypeBackfillMigrator : IDataMigrator { public int Order => 10; public string Name => "SimpleFields.CarTypeBackfill"; public async Task MigrateAsync(DbContext db, CancellationToken ct = default) { if (db is not MiGuDbContext ctx) return; await ctx.SimpleFields .Where(x => (x.CarType == null || x.CarType == "") && x.Other != "") .ExecuteUpdateAsync(s => s.SetProperty(x => x.CarType, x => x.Other), ct); await ctx.SimpleFields .Where(x => x.Other != "" && x.Other == x.CarType) .ExecuteUpdateAsync(s => s.SetProperty(x => x.Other, ""), ct); } } /// /// 把库内旧状态字符串刷成规范枚举名(Available/Idle→Empty,Occupied→FullContainer)。 /// 仅 Sqlite 表名/列名;绕过枚举 HasConversion(ExecuteUpdate + 字符串比较会 InvalidCast)。 /// public sealed class LegacyStatusNormalizationMigrator : IDataMigrator { public int Order => 15; public string Name => "Wms.LegacyStatusNormalization"; public async Task MigrateAsync(DbContext db, CancellationToken ct = default) { if (db is not MiGuDbContext) return; await db.Database.ExecuteSqlRawAsync( """ UPDATE wms_storages SET Status = 'Empty' WHERE Status IN ('Available', 'Idle') """, ct); await db.Database.ExecuteSqlRawAsync( """ UPDATE wms_storages SET Status = 'FullContainer' WHERE Status = 'Occupied' """, ct); await db.Database.ExecuteSqlRawAsync( """ UPDATE wms_areas SET LayoutMode = 'Flat' WHERE LayoutMode IS NULL OR LayoutMode = '' """, ct); } } /// /// LocationType=Storage 时回填 StorageId,供库存 join;写路径 BindOrTransferLocation 也会维护该字段。 /// public sealed class ContainerLocationStorageIdBackfillMigrator : IDataMigrator { public int Order => 20; public string Name => "Wms.ContainerLocation.StorageId"; public async Task MigrateAsync(DbContext db, CancellationToken ct = default) { if (db is not MiGuDbContext ctx) return; var rows = await ctx.ContainerLocations .Where(x => x.LocationType == ContainerLocationType.Storage && x.StorageId == null) .ToListAsync(ct); foreach (var row in rows) { if (Guid.TryParse(row.LocationId, out var sid)) row.StorageId = sid; } if (rows.Count > 0) await ctx.SaveChangesAsync(ct); } } public static class DataMigratorRegistration { public static IServiceCollection AddMiGuDataMigrators(this IServiceCollection services) { services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); return services; } }