Files
Migu2.0/MiGu.DB/Domains/Migrators/DataMigrators.cs
T
wei.wu 51c3fc1994 持久层重构为独立 MiGu.DB 工程并优化集成
- 新增 MiGu.DB 项目,迁移所有领域实体与枚举,统一模型约定
- 实现 Entity/Repository/UoW/Provider/Exception 等接口与实现
- 支持数据修补机制,完善 Sqlite 初始迁移与数据库管理
- Server 侧移除 EF Core 相关,依赖 MiGu.DB,PlatformPersistence 适配
- 业务服务注入 UoW/Repository,状态字段统一用 enum 及辅助类
- 统一异常处理,Controller 映射 HTTP 状态码
- 配置项与文档补充数据库启动、SchemaMode、迁移说明
- 新增 GlobalUsings.Db.cs、WmsStatusAliases.cs 简化类型引用
- 新增 HttpActorContextMiddleware 支持操作者上下文一致性
- 新增 MiGuDbContextModelSnapshot 追踪数据库结构
- 优化代码结构,解耦领域与持久层,提升扩展性与安全性
2026-07-27 14:26:04 +08:00

106 lines
3.6 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;
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 UPDATESqlite)。
/// <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→EmptyOccupied→FullContainer)。
/// 仅 Sqlite 表名/列名;绕过枚举 HasConversionExecuteUpdate + 字符串比较会 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;
}
}