Browse Source

Add SQLite busy timeout support and interceptor

pull/24343/head
maliming 9 months ago
parent
commit
5caaa2b6f5
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 6
      framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/AbpSqliteOptions.cs
  2. 39
      framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Interceptors/SqliteBusyTimeoutSaveChangesInterceptor.cs
  3. 22
      framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Sqlite/AbpEntityFrameworkCoreSqliteModule.cs
  4. 41
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs

6
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; }
}

39
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;
/// <summary>
/// https://github.com/dotnet/efcore/issues/29514
/// </summary>
public class SqliteBusyTimeoutSaveChangesInterceptor : SaveChangesInterceptor
{
private readonly string _pragmaCommand;
public SqliteBusyTimeoutSaveChangesInterceptor(int timeoutMilliseconds)
{
_pragmaCommand = $"PRAGMA busy_timeout={timeoutMilliseconds};";
}
public override InterceptionResult<int> SavingChanges(DbContextEventData eventData, InterceptionResult<int> result)
{
if (eventData.Context != null)
{
eventData.Context.Database.ExecuteSqlRaw(_pragmaCommand);
}
return result;
}
public override async ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken = default)
{
if (eventData.Context != null)
{
await eventData.Context.Database.ExecuteSqlRawAsync(_pragmaCommand, cancellationToken: cancellationToken);
}
return await base.SavingChangesAsync(eventData, result, cancellationToken);
}
}

22
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<AbpSqliteOptions>(options =>
{
options.BusyTimeout = 5000;
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpEfCoreGlobalFilterOptions>(options =>
{
options.UseDbFunction = true;
});
var sqliteOptions = context.Services.ExecutePreConfiguredActions<AbpSqliteOptions>();
if (sqliteOptions.BusyTimeout.HasValue)
{
Configure<AbpDbContextOptions>(options =>
{
options.ConfigureDefaultOnConfiguring((dbContext, dbContextOptionsBuilder) =>
{
dbContextOptionsBuilder.AddInterceptors(new SqliteBusyTimeoutSaveChangesInterceptor(sqliteOptions.BusyTimeout.Value));
}, overrideExisting: false);
});
}
}
}

41
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs

@ -26,11 +26,11 @@ public class AbpDbContextOptions
internal Dictionary<Type, List<object>> ConventionActions { get; }
internal Action<DbContext, ModelBuilder>? DefaultOnModelCreatingAction { get; set; }
internal Action<DbContext, DbContextOptionsBuilder>? DefaultOnConfiguringAction { get; set; }
internal Dictionary<Type, List<object>> OnModelCreatingActions { get; }
internal Dictionary<Type, List<object>> OnConfiguringActions { get; }
public AbpDbContextOptions()
@ -58,11 +58,18 @@ public class AbpDbContextOptions
DefaultConfigureAction = action;
}
public void ConfigureDefaultConvention([NotNull] Action<DbContext, ModelConfigurationBuilder> action)
public void ConfigureDefaultConvention([NotNull] Action<DbContext, ModelConfigurationBuilder> action, bool overrideExisting = false)
{
Check.NotNull(action, nameof(action));
DefaultConventionAction = action;
if (overrideExisting)
{
DefaultConventionAction = action;
}
else
{
DefaultConventionAction += action;
}
}
public void ConfigureConventions<TDbContext>([NotNull] Action<TDbContext, ModelConfigurationBuilder> action)
@ -83,18 +90,32 @@ public class AbpDbContextOptions
actions.Add(action);
}
public void ConfigureDefaultOnModelCreating([NotNull] Action<DbContext, ModelBuilder> action)
public void ConfigureDefaultOnModelCreating([NotNull] Action<DbContext, ModelBuilder> action, bool overrideExisting = false)
{
Check.NotNull(action, nameof(action));
DefaultOnModelCreatingAction = action;
if (overrideExisting)
{
DefaultOnModelCreatingAction = action;
}
else
{
DefaultOnModelCreatingAction += action;
}
}
public void ConfigureDefaultOnConfiguring([NotNull] Action<DbContext, DbContextOptionsBuilder> action)
public void ConfigureDefaultOnConfiguring([NotNull] Action<DbContext, DbContextOptionsBuilder> action, bool overrideExisting = false)
{
Check.NotNull(action, nameof(action));
DefaultOnConfiguringAction = action;
if (overrideExisting)
{
DefaultOnConfiguringAction = action;
}
else
{
DefaultOnConfiguringAction += action;
}
}
public void ConfigureOnModelCreating<TDbContext>([NotNull] Action<TDbContext, ModelBuilder> action)
@ -114,7 +135,7 @@ public class AbpDbContextOptions
actions.Add(action);
}
public void ConfigureOnConfiguring<TDbContext>([NotNull] Action<TDbContext, DbContextOptionsBuilder> action)
where TDbContext : AbpDbContext<TDbContext>
{

Loading…
Cancel
Save