- 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
64 lines
2.6 KiB
C#
64 lines
2.6 KiB
C#
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;
|
||
}
|
||
}
|