- 新增 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 追踪数据库结构 - 优化代码结构,解耦领域与持久层,提升扩展性与安全性
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;
|
||
}
|
||
}
|