106 lines
3.6 KiB
C#
106 lines
3.6 KiB
C#
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)。
|
|||
|
|
|
|||
|
|
/// <summary>将 simple_fields.other 回填到 car_type(替代原 PlatformPersistence raw UPDATE)。</summary>
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 把库内旧状态字符串刷成规范枚举名(Available/Idle→Empty,Occupied→FullContainer)。
|
|||
|
|
/// 仅 Sqlite 表名/列名;绕过枚举 HasConversion(ExecuteUpdate + 字符串比较会 InvalidCast)。
|
|||
|
|
/// </summary>
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// LocationType=Storage 时回填 StorageId,供库存 join;写路径 BindOrTransferLocation 也会维护该字段。
|
|||
|
|
/// </summary>
|
|||
|
|
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<IDataMigrator, SimpleFieldsCarTypeBackfillMigrator>();
|
|||
|
|
services.AddSingleton<IDataMigrator, LegacyStatusNormalizationMigrator>();
|
|||
|
|
services.AddSingleton<IDataMigrator, ContainerLocationStorageIdBackfillMigrator>();
|
|||
|
|
return services;
|
|||
|
|
}
|
|||
|
|
}
|