diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/AbpSqliteOptions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/AbpSqliteOptions.cs
new file mode 100644
index 0000000000..2d94b2864a
--- /dev/null
+++ b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/AbpSqliteOptions.cs
@@ -0,0 +1,6 @@
+namespace Volo.Abp.EntityFrameworkCore;
+
+public class AbpSqliteOptions
+{
+ public int? BusyTimeout { get; set; }
+}
diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Interceptors/SqliteBusyTimeoutSaveChangesInterceptor.cs b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Interceptors/SqliteBusyTimeoutSaveChangesInterceptor.cs
new file mode 100644
index 0000000000..32b4859bbb
--- /dev/null
+++ b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Interceptors/SqliteBusyTimeoutSaveChangesInterceptor.cs
@@ -0,0 +1,39 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+
+namespace Volo.Abp.EntityFrameworkCore.Interceptors;
+
+///
+/// https://github.com/dotnet/efcore/issues/29514
+///
+public class SqliteBusyTimeoutSaveChangesInterceptor : SaveChangesInterceptor
+{
+ private readonly string _pragmaCommand;
+
+ public SqliteBusyTimeoutSaveChangesInterceptor(int timeoutMilliseconds)
+ {
+ _pragmaCommand = $"PRAGMA busy_timeout={timeoutMilliseconds};";
+ }
+
+ public override InterceptionResult SavingChanges(DbContextEventData eventData, InterceptionResult result)
+ {
+ if (eventData.Context != null)
+ {
+ eventData.Context.Database.ExecuteSqlRaw(_pragmaCommand);
+ }
+
+ return result;
+ }
+
+ public override async ValueTask> SavingChangesAsync(DbContextEventData eventData, InterceptionResult result, CancellationToken cancellationToken = default)
+ {
+ if (eventData.Context != null)
+ {
+ await eventData.Context.Database.ExecuteSqlRawAsync(_pragmaCommand, cancellationToken: cancellationToken);
+ }
+
+ return await base.SavingChangesAsync(eventData, result, cancellationToken);
+ }
+}
diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Sqlite/AbpEntityFrameworkCoreSqliteModule.cs b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Sqlite/AbpEntityFrameworkCoreSqliteModule.cs
index 52415d73b1..6b767ceee4 100644
--- a/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Sqlite/AbpEntityFrameworkCoreSqliteModule.cs
+++ b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Sqlite/AbpEntityFrameworkCoreSqliteModule.cs
@@ -1,4 +1,6 @@
+using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore.GlobalFilters;
+using Volo.Abp.EntityFrameworkCore.Interceptors;
using Volo.Abp.Modularity;
namespace Volo.Abp.EntityFrameworkCore.Sqlite;
@@ -8,11 +10,31 @@ namespace Volo.Abp.EntityFrameworkCore.Sqlite;
)]
public class AbpEntityFrameworkCoreSqliteModule : AbpModule
{
+ public override void PreConfigureServices(ServiceConfigurationContext context)
+ {
+ PreConfigure(options =>
+ {
+ options.BusyTimeout = 5000;
+ });
+ }
+
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure(options =>
{
options.UseDbFunction = true;
});
+
+ var sqliteOptions = context.Services.ExecutePreConfiguredActions();
+ if (sqliteOptions.BusyTimeout.HasValue)
+ {
+ Configure(options =>
+ {
+ options.ConfigureDefaultOnConfiguring((dbContext, dbContextOptionsBuilder) =>
+ {
+ dbContextOptionsBuilder.AddInterceptors(new SqliteBusyTimeoutSaveChangesInterceptor(sqliteOptions.BusyTimeout.Value));
+ }, overrideExisting: false);
+ });
+ }
}
}
diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs
index a179bb3ee8..75cf409608 100644
--- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs
+++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs
@@ -26,11 +26,11 @@ public class AbpDbContextOptions
internal Dictionary> ConventionActions { get; }
internal Action? DefaultOnModelCreatingAction { get; set; }
-
+
internal Action? DefaultOnConfiguringAction { get; set; }
internal Dictionary> OnModelCreatingActions { get; }
-
+
internal Dictionary> OnConfiguringActions { get; }
public AbpDbContextOptions()
@@ -58,11 +58,18 @@ public class AbpDbContextOptions
DefaultConfigureAction = action;
}
- public void ConfigureDefaultConvention([NotNull] Action action)
+ public void ConfigureDefaultConvention([NotNull] Action action, bool overrideExisting = false)
{
Check.NotNull(action, nameof(action));
- DefaultConventionAction = action;
+ if (overrideExisting)
+ {
+ DefaultConventionAction = action;
+ }
+ else
+ {
+ DefaultConventionAction += action;
+ }
}
public void ConfigureConventions([NotNull] Action action)
@@ -83,18 +90,32 @@ public class AbpDbContextOptions
actions.Add(action);
}
- public void ConfigureDefaultOnModelCreating([NotNull] Action action)
+ public void ConfigureDefaultOnModelCreating([NotNull] Action action, bool overrideExisting = false)
{
Check.NotNull(action, nameof(action));
- DefaultOnModelCreatingAction = action;
+ if (overrideExisting)
+ {
+ DefaultOnModelCreatingAction = action;
+ }
+ else
+ {
+ DefaultOnModelCreatingAction += action;
+ }
}
-
- public void ConfigureDefaultOnConfiguring([NotNull] Action action)
+
+ public void ConfigureDefaultOnConfiguring([NotNull] Action action, bool overrideExisting = false)
{
Check.NotNull(action, nameof(action));
- DefaultOnConfiguringAction = action;
+ if (overrideExisting)
+ {
+ DefaultOnConfiguringAction = action;
+ }
+ else
+ {
+ DefaultOnConfiguringAction += action;
+ }
}
public void ConfigureOnModelCreating([NotNull] Action action)
@@ -114,7 +135,7 @@ public class AbpDbContextOptions
actions.Add(action);
}
-
+
public void ConfigureOnConfiguring([NotNull] Action action)
where TDbContext : AbpDbContext
{