diff --git a/assets/res/NetAdmin.Statements.ln b/assets/res/NetAdmin.Statements.ln
index 6aafb9b4..f50f2ded 100644
--- a/assets/res/NetAdmin.Statements.ln
+++ b/assets/res/NetAdmin.Statements.ln
@@ -15,6 +15,8 @@ XML注释文件不存在
时间表达式
用户名不能是手机号码
用户名长度4位以上
+种子数据插入完成
+记录已存在
请求对象不能为空
邀请码不正确
配置文件初始化完毕
diff --git a/src/backend/NetAdmin.Domain/Events/SeedDataInsertedEvent.cs b/src/backend/NetAdmin.Domain/Events/SeedDataInsertedEvent.cs
new file mode 100644
index 00000000..9279fcc9
--- /dev/null
+++ b/src/backend/NetAdmin.Domain/Events/SeedDataInsertedEvent.cs
@@ -0,0 +1,36 @@
+namespace NetAdmin.Domain.Events;
+
+///
+/// 种子数据插入完毕事件
+///
+public sealed record SeedDataInsertedEvent : DataAbstraction, IEventSource
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SeedDataInsertedEvent(int insertedCount)
+ {
+ InsertedCount = insertedCount;
+ EventId = nameof(SeedDataInsertedEvent);
+ }
+
+ ///
+ public CancellationToken CancellationToken { get; }
+
+ ///
+ public DateTime CreatedTime { get; }
+
+ ///
+ public string EventId { get; }
+
+ ///
+ public bool IsConsumOnce { get; }
+
+ ///
+ public object Payload { get; }
+
+ ///
+ /// 插入数量
+ ///
+ public int InsertedCount { get; set; }
+}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Host/Filters/ApiResultHandler.cs b/src/backend/NetAdmin.Host/Filters/ApiResultHandler.cs
index cc242292..edd7d494 100644
--- a/src/backend/NetAdmin.Host/Filters/ApiResultHandler.cs
+++ b/src/backend/NetAdmin.Host/Filters/ApiResultHandler.cs
@@ -23,8 +23,13 @@ public abstract class ApiResultHandler
///
public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata)
{
- var naException = context.Exception switch { NetAdminException ex => ex, _ => null };
- var errorCode = naException?.Code ?? ErrorCodes.Unhandled;
+ var naException = context.Exception switch {
+ NetAdminException ex => ex
+ , _ => context.Exception.Message.Contains(Chars.FLG_DB_EXCEPTION_PRIMARY_KEY_CONFLICT)
+ ? new NetAdminInvalidOperationException(Ln.记录已存在)
+ : null
+ };
+ var errorCode = naException?.Code ?? ErrorCodes.Unhandled;
var result = RestfulResult(errorCode, metadata.Data
, naException is NetAdminValidateException vEx
? vEx.ValidateResults
diff --git a/src/backend/NetAdmin.Host/Subscribers/SqlProfiler.cs b/src/backend/NetAdmin.Host/Subscribers/SqlProfiler.cs
index 78ebe786..1dbff877 100644
--- a/src/backend/NetAdmin.Host/Subscribers/SqlProfiler.cs
+++ b/src/backend/NetAdmin.Host/Subscribers/SqlProfiler.cs
@@ -29,6 +29,21 @@ public sealed class SqlProfiler(ILogger logger) : IEventSubscriber
return Task.CompletedTask;
}
+ ///
+ /// 种子数据插入完毕
+ ///
+ [EventSubscribe(nameof(SeedDataInsertedEvent))]
+ public Task SeedDataInsertedEventAsync(EventHandlerExecutingContext context)
+ {
+ var source = context.Source as SeedDataInsertedEvent;
+ logger.Info(source);
+ if (App.WebHostEnvironment.IsDevelopment()) {
+ Environment.Exit(0);
+ }
+
+ return Task.CompletedTask;
+ }
+
///
/// 同步数据库结构之后
///
diff --git a/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs b/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs
index 824894cb..5d660e8e 100644
--- a/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs
+++ b/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs
@@ -15,7 +15,7 @@ public static class Chars
public const string FLG_CONTEXT_USER_ID = nameof(FLG_CONTEXT_USER_ID);
public const string FLG_CONTEXT_USER_INFO = nameof(FLG_CONTEXT_USER_INFO);
public const string FLG_CRON_PER_SECS = "* * * * * *";
- public const string FLG_DB_EXCEPTION_PRIVATE_KEY_CONFLICT = "PRIMARY KEY";
+ public const string FLG_DB_EXCEPTION_PRIMARY_KEY_CONFLICT = "PRIMARY KEY";
public const string FLG_DB_FIELD_TYPE_NVARCHAR = "nvarchar";
public const string FLG_DB_FIELD_TYPE_NVARCHAR_1022 = "nvarchar(1022)";
public const string FLG_DB_FIELD_TYPE_NVARCHAR_127 = "nvarchar(127)";
diff --git a/src/backend/NetAdmin.Infrastructure/Utils/FreeSqlBuilder.cs b/src/backend/NetAdmin.Infrastructure/Utils/FreeSqlBuilder.cs
index cb86ee6f..e5e58b8e 100644
--- a/src/backend/NetAdmin.Infrastructure/Utils/FreeSqlBuilder.cs
+++ b/src/backend/NetAdmin.Infrastructure/Utils/FreeSqlBuilder.cs
@@ -13,7 +13,7 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions)
///
/// 构建freeSql对象
///
- public IFreeSql Build(FreeSqlInitMethods initMethods)
+ public IFreeSql Build(FreeSqlInitMethods initMethods, Func onSeedDataInserted = null)
{
var freeSql = new FreeSql.FreeSqlBuilder()
#if DBTYPE_SQLSERVER
@@ -25,7 +25,7 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions)
.UseGenerateCommandParameterWithLambda(true)
.UseAutoSyncStructure(initMethods.HasFlag(FreeSqlInitMethods.SyncStructure))
.Build();
- _ = InitDbAsync(freeSql, initMethods); // 初始化数据库 ,异步
+ _ = InitDbAsync(freeSql, initMethods, onSeedDataInserted); // 初始化数据库 ,异步
return freeSql;
}
@@ -69,7 +69,7 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions)
///
/// 初始化数据库
///
- private Task InitDbAsync(IFreeSql freeSql, FreeSqlInitMethods initMethods)
+ private Task InitDbAsync(IFreeSql freeSql, FreeSqlInitMethods initMethods, Func onSeedDataInserted)
{
return Task.Run(() => {
if (initMethods == FreeSqlInitMethods.None) {
@@ -82,7 +82,8 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions)
}
if (initMethods.HasFlag(FreeSqlInitMethods.InsertSeedData)) {
- InsertSeedData(freeSql, entityTypes);
+ var insertCount = InsertSeedData(freeSql, entityTypes);
+ _ = onSeedDataInserted?.Invoke(insertCount);
}
if (initMethods.HasFlag(FreeSqlInitMethods.CompareStructure)) {
@@ -94,8 +95,9 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions)
///
/// 插入种子数据
///
- private void InsertSeedData(IFreeSql freeSql, IEnumerable entityTypes)
+ private int InsertSeedData(IFreeSql freeSql, IEnumerable entityTypes)
{
+ var ret = 0;
foreach (var entityType in entityTypes) {
var file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, databaseOptions.SeedDataRelativePath, $"{entityType.Name}.json");
if (!File.Exists(file)) {
@@ -112,8 +114,8 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions)
};
_ = jsonSerializerOptions.Converters.AddDateTimeTypeConverters();
- var jsonTypeInfo = JsonTypeInfo.CreateJsonTypeInfo(typeof(IEnumerable<>).MakeGenericType(entityType), jsonSerializerOptions);
- var entities = JsonSerializer.Deserialize(fs, jsonTypeInfo);
+ var jsonTypeInfo = JsonTypeInfo.CreateJsonTypeInfo(typeof(IEnumerable<>).MakeGenericType(entityType), jsonSerializerOptions);
+ dynamic entities = JsonSerializer.Deserialize(fs, jsonTypeInfo);
// 如果表存在数据,跳过
var select = typeof(IFreeSql).GetMethod(nameof(freeSql.Select), 1, Type.EmptyTypes)?.MakeGenericMethod(entityType).Invoke(freeSql, null);
@@ -129,8 +131,11 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions)
var insert = MakeInsertMethod(entityType);
- _ = insert?.Invoke(rep, [entities]);
+ _ = insert?.Invoke(rep, [entities]);
+ ret += entities!.Count;
}
+
+ return ret;
}
///
diff --git a/src/backend/NetAdmin.SysComponent.Host/Extensions/ServiceCollectionExtensions.cs b/src/backend/NetAdmin.SysComponent.Host/Extensions/ServiceCollectionExtensions.cs
index 0176da1e..1e47132f 100644
--- a/src/backend/NetAdmin.SysComponent.Host/Extensions/ServiceCollectionExtensions.cs
+++ b/src/backend/NetAdmin.SysComponent.Host/Extensions/ServiceCollectionExtensions.cs
@@ -32,12 +32,13 @@ public static class ServiceCollectionExtensions
// #if !DEBUG
// initOptions = FreeSqlInitOptions.None;
// #endif
- var dbOptions = App.GetOptions();
- var fSql = new FreeSqlBuilder(dbOptions).Build(initMethods);
+ var dbOptions = App.GetOptions();
+ var eventPublisher = App.GetService();
+
+ var fSql = new FreeSqlBuilder(dbOptions).Build(initMethods, count => eventPublisher.PublishAsync(new SeedDataInsertedEvent(count)));
_ = me.AddSingleton(fSql);
fSql.Aop.AuditValue += SqlAuditor.DataAuditHandler; // Insert/Update自动值处理
- var eventPublisher = App.GetService();
#pragma warning disable VSTHRD110