xiangning d1c8988054 feat(scripting): 迁移 Domain 实体+EF 配置+表重命名迁移
- ScriptFunction/ScriptExecutionLog 实体(从 CustomFunction 迁移)
- ScriptStatus/ScriptExecutionStatus 枚举
- ScriptingDbContext + 两个 Configuration(表名 funcs/func_execution_logs)
- EF Core 迁移:RenameTablesForScriptingModule(b_funcs→funcs 保数据)
- 新增 LogLines 字段(Logger 输出收集)

Task T2 of scripting module refactor
2026-07-06 17:56:40 +08:00

64 lines
2.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 System.Linq.Expressions;
using BuildFlow.Shared.Domain.Common;
using BuildFlow.Shared.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Scripting.Domain.Entities;
namespace Scripting.Infrastructure.Persistence;
/// <summary>
/// Scripting 持久化上下文。承载脚本函数定义与执行日志。
/// 注册 AuditInterceptor 自动维护审计字段;对实现 ISoftDelete 的实体统一生成全局查询过滤器,
/// 自动排除已软删除记录。约定与 WorkflowDbContext 保持一致。
/// </summary>
public class ScriptingDbContext : DbContext
{
private readonly ICurrentUserContext? _currentUserContext;
public DbSet<ScriptFunction> Scripts => Set<ScriptFunction>();
public DbSet<ScriptExecutionLog> ScriptExecutionLogs => Set<ScriptExecutionLog>();
public ScriptingDbContext(DbContextOptions<ScriptingDbContext> options) : base(options) { }
public ScriptingDbContext(DbContextOptions<ScriptingDbContext> options, ICurrentUserContext currentUserContext)
: base(options)
{
_currentUserContext = currentUserContext;
}
// 注意:此处通过 OnConfiguring 注册拦截器(而非 DI AddInterceptors),与 rag-backend 约定一致,
// 保证无参构造(如设计时工厂、测试夹具)也能正常工作。
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (_currentUserContext is not null)
{
optionsBuilder.AddInterceptors(new AuditInterceptor(_currentUserContext));
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 自动发现本程序集内所有 IEntityTypeConfiguration 实现
modelBuilder.ApplyConfigurationsFromAssembly(typeof(ScriptingDbContext).Assembly);
// 为所有实现 ISoftDelete 的实体动态生成 HasQueryFilter(e => !e.IsDeleted)
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
if (typeof(ISoftDelete).IsAssignableFrom(entityType.ClrType))
{
modelBuilder.Entity(entityType.ClrType).HasQueryFilter(
CreateSoftDeleteFilter(entityType.ClrType));
}
}
}
/// <summary>用表达式树动态构造 e => !e.IsDeleted,避免对每个实体类型手写泛型过滤。</summary>
private static LambdaExpression CreateSoftDeleteFilter(Type entityType)
{
var param = Expression.Parameter(entityType, "e");
var isDeletedProp = Expression.Property(param, nameof(ISoftDelete.IsDeleted));
var filter = Expression.Lambda(Expression.Not(isDeletedProp), param);
return filter;
}
}