66
77namespace EntityFrameworkCore . Sqlite . Concurrency ;
88
9+ /// <summary>
10+ /// Extension methods for configuring SQLite concurrency and performance in EF Core.
11+ /// </summary>
912public static class SqliteConcurrencyExtensions
1013{
11- public static DbContextOptionsBuilder UseSqliteWithConcurrency (
12- this DbContextOptionsBuilder optionsBuilder ,
13- string connectionString ,
14- Action < SqliteConcurrencyOptions > ? configure = null )
15- {
16- var options = new SqliteConcurrencyOptions ( ) ;
17- configure ? . Invoke ( options ) ;
18-
19- // Get the enhanced connection string
20- var enhancedConnectionString = SqliteConnectionEnhancer
21- . GetOptimizedConnectionString ( connectionString ) ;
22-
23- // Create a configured connection
24- var connection = new SqliteConnection ( enhancedConnectionString ) ;
25-
26- // Apply optimizations when connection opens
27- connection . StateChange += ( sender , args ) =>
28- {
29- if ( args . OriginalState == ConnectionState . Closed &&
30- args . CurrentState == ConnectionState . Open )
31- {
32- if ( sender is SqliteConnection sqliteConnection )
33- {
34- // Apply runtime pragmas
35- SqliteConnectionEnhancer . ApplyRuntimePragmas ( sqliteConnection , options ) ;
36-
37- // Set busy timeout
38- SetBusyTimeout ( sqliteConnection , options . BusyTimeout ) ;
39-
40- // Additional optimizations
41- ConfigureForWriteQueue ( sqliteConnection ) ;
42- SetWalCheckpoint ( sqliteConnection , options . WalAutoCheckpoint ) ;
43- }
44- }
45- } ;
14+ /// <summary>
15+ /// Configures the context to use SQLite with optimized concurrency and performance settings.
16+ /// </summary>
17+ /// <param name="optionsBuilder">The options builder.</param>
18+ /// <param name="connectionString">The SQLite connection string.</param>
19+ /// <param name="configure">An optional action to configure concurrency options.</param>
20+ /// <returns>The options builder.</returns>
21+ public static DbContextOptionsBuilder UseSqliteWithConcurrency (
22+ this DbContextOptionsBuilder optionsBuilder ,
23+ string connectionString ,
24+ Action < SqliteConcurrencyOptions > ? configure = null )
25+ {
26+ var options = new SqliteConcurrencyOptions ( ) ;
27+ configure ? . Invoke ( options ) ;
4628
47- // Use the configured connection with EF Core
48- optionsBuilder . UseSqlite ( connection , sqliteOptions =>
49- {
50- // Configure command timeout
51- sqliteOptions . CommandTimeout ( options . CommandTimeout ) ;
52- } ) ;
53-
54- // Always add interceptors for write queue
55- var interceptor = SqliteConnectionEnhancer . GetInterceptor ( enhancedConnectionString , options ) ;
56- optionsBuilder . AddInterceptors ( interceptor ) ;
57-
58- return optionsBuilder ;
59- }
29+ // Get the enhanced connection string
30+ var enhancedConnectionString = SqliteConnectionEnhancer
31+ . GetOptimizedConnectionString ( connectionString ) ;
32+
33+ // Use the connection string with EF Core to allow proper pooling
34+ optionsBuilder . UseSqlite ( enhancedConnectionString , sqliteOptions =>
35+ {
36+ // Configure command timeout
37+ sqliteOptions . CommandTimeout ( options . CommandTimeout ) ;
38+ } ) ;
39+
40+ // Add interceptors for PRAGMAs, performance, and concurrency
41+ var interceptor = SqliteConnectionEnhancer . GetInterceptor ( enhancedConnectionString , options ) ;
42+ optionsBuilder . AddInterceptors ( interceptor ) ;
43+
44+ return optionsBuilder ;
45+ }
6046
6147
6248
49+ /// <summary>
50+ /// Executes an operation with automatic retry on SQLITE_BUSY errors.
51+ /// </summary>
52+ /// <typeparam name="T">The result type.</typeparam>
53+ /// <param name="context">The database context.</param>
54+ /// <param name="operation">The operation to execute.</param>
55+ /// <param name="maxRetries">The maximum number of retries.</param>
56+ /// <param name="cancellationToken">The cancellation token.</param>
57+ /// <returns>The result of the operation.</returns>
6358 public static async Task < T > ExecuteWithRetryAsync < T > (
6459 this DbContext context ,
6560 Func < DbContext , Task < T > > operation ,
@@ -81,6 +76,13 @@ public static async Task<T> ExecuteWithRetryAsync<T>(
8176 }
8277 }
8378
79+ /// <summary>
80+ /// Performs a bulk insert with optimized settings and optional app-level locking.
81+ /// </summary>
82+ /// <typeparam name="T">The entity type.</typeparam>
83+ /// <param name="context">The database context.</param>
84+ /// <param name="entities">The entities to insert.</param>
85+ /// <param name="cancellationToken">The cancellation token.</param>
8486 public static async Task BulkInsertOptimizedAsync < T > (
8587 this DbContext context ,
8688 IEnumerable < T > entities ,
@@ -122,28 +124,4 @@ public static async Task BulkInsertOptimizedAsync<T>(
122124 writeLock . Release ( ) ;
123125 }
124126 }
125-
126- private static void ConfigureForWriteQueue ( SqliteConnection connection )
127- {
128- using var command = connection . CreateCommand ( ) ;
129- command . CommandText = @"
130- PRAGMA cache_size = -2000;
131- PRAGMA page_size = 4096;
132- " ;
133- command . ExecuteNonQuery ( ) ;
134- }
135-
136- private static void SetBusyTimeout ( SqliteConnection connection , TimeSpan timeout )
137- {
138- using var command = connection . CreateCommand ( ) ;
139- command . CommandText = $ "PRAGMA busy_timeout = { ( int ) timeout . TotalMilliseconds } ;";
140- command . ExecuteNonQuery ( ) ;
141- }
142-
143- private static void SetWalCheckpoint ( SqliteConnection connection , int checkpointPages )
144- {
145- using var command = connection . CreateCommand ( ) ;
146- command . CommandText = $ "PRAGMA wal_autocheckpoint = { checkpointPages } ;";
147- command . ExecuteNonQuery ( ) ;
148- }
149127}
0 commit comments