Skip to content

Conversation

@ysmoradi
Copy link
Member

@ysmoradi ysmoradi commented Nov 30, 2025

closes #11775

Summary by CodeRabbit

  • New Features

    • Added optional service lifetime parameter for database context factory configuration.
  • Bug Fixes

    • Refined SQL command detection for targeted database operations.
  • Chores

    • Renamed JavaScript persistence methods (besqlPersist, besqlLoad).
    • Updated database migrations and infrastructure dependencies.
    • Suppressed internal compiler warnings.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 30, 2025

Walkthrough

The PR refactors the Besql DbContext factory implementation from PooledDbContextFactoryBase to DbContextFactoryBase, replacing the inherited PooledDbContextFactory<TDbContext> with direct implementation of IDbContextFactory<TDbContext>. This enables resolution of scoped dependency-injection services. Supporting changes include constructor parameter reordering, method renames in JavaScript, updated service registration, and EF Core migration updates.

Changes

Cohort / File(s) Summary
Factory Implementation
src/Besql/Bit.Besql/BesqlDbContextFactory.cs, src/Besql/Bit.Besql/DbContextFactoryBase.cs
Base class changed from PooledDbContextFactoryBase to DbContextFactoryBase implementing IDbContextFactory<TDbContext>. Constructor signatures refactored: serviceProvider, options, factorySource, and dbContextInitializer reordered; storage moved to final parameter. CreateDbContextAsync and CreateDbContext now virtual and use factorySource.Factory(serviceProvider, options) for instance creation.
Service Registration
src/Besql/Bit.Besql/IServiceCollectionBesqlExtentions.cs
AddBesqlDbContextFactory overloads extended with ServiceLifetime lifetime = ServiceLifetime.Singleton parameter. Factory type references updated to BesqlDbContextFactory<TDbContext> and DbContextFactoryBase<TDbContext>. Parameter propagation adjusted in overload delegation.
SQL Interception
src/Besql/Bit.Besql/BesqlDbContextInterceptor.cs
SQL keywords array updated to include trailing spaces/phrases: "INSERT""INSERT INTO ", "UPDATE""UPDATE ", "DELETE""DELETE FROM ", refining targeted command detection.
Warnings Suppression
src/Besql/Bit.Besql/Bit.Besql.csproj
Added NoWarn entry to suppress IL2091 and EF1001 compiler warnings across all target frameworks.
JavaScript API
src/Besql/Bit.Besql/wwwroot/bit-besql.js
Public methods renamed: BitBesql.persist(fileName)BitBesql.besqlPersist(fileName), BitBesql.load(fileName)BitBesql.besqlLoad(fileName). besqlPersist enhanced with file-existence validation, blob creation, response headers, and cache storage at /data/cache/${fileName}.
Demo EF Core Model
src/Besql/Demo/Bit.Besql.Demo.Client/Data/CompiledModel/OfflineDbContextModelBuilder.cs
Model ID updated (ac96847b-e3a9-46a3-82cf-7605a37f26afa517c835-3ee2-49c8-b15c-99478d0fbb8b). ProductVersion annotation incremented from 9.0.0 to 10.0.0.
Demo Migrations
src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/20240105010046_InitialMigration.Designer.cs
Deleted obsolete migration designer file.
Demo Migrations
src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/20251130123559_Initial.Designer.cs, src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/20251130123559_Initial.cs
Added new migration designer and implementation for Initial migration, replacing prior naming convention. Includes WeatherForecast entity configuration with properties, seeding, and indexes. ProductVersion set to 10.0.0.
Demo Migration Snapshot
src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/OfflineDbContextModelSnapshot.cs
Namespace syntax updated to semicolon-terminated style. Attribute placement adjusted. ProductVersion annotation updated from 8.0.0 to 10.0.0. Model structure unchanged.
Demo Service Configuration
src/Besql/Demo/Bit.Besql.Demo.Client/Extensions/ServiceCollectionExtensions.cs
Model reference fully qualified from OfflineDbContextModel.Instance to Bit.Besql.Demo.Client.Data.CompiledModel.OfflineDbContextModel.Instance. Unused using directive removed.
Demo Project
src/Besql/Demo/Bit.Besql.Demo/Bit.Besql.Demo.csproj
Removed Microsoft.EntityFrameworkCore.Design (v10.0.0) PackageReference.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Base class and constructor refactoring (DbContextFactoryBase.cs, BesqlDbContextFactory.cs): Verify parameter ordering, base constructor invocation compatibility, and IDbContextFactorySource<TDbContext> usage pattern.
  • Service registration propagation (IServiceCollectionBesqlExtentions.cs): Confirm ServiceLifetime parameter threading through overload delegation and correct factory type mappings.
  • JavaScript method naming and validation (bit-besql.js): Validate file-existence checks, blob creation, and cache storage logic in besqlPersist.
  • EF Core migration updates: Verify model ID, ProductVersion consistency, and entity configuration integrity across migration files and snapshots.

Poem

🐰 Pooled no more, now scoped we go!
Services flow through DI's glow—
Factories dance with every call,
Scoped dependencies resolved for all.
Hop hop—the refactor's done! ✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Multiple out-of-scope changes detected: SQL keyword pattern matching modifications, JavaScript method renames, migration class renames, and EF Core version upgrades unrelated to the core objective of enabling scoped service resolution. Separate cosmetic/secondary changes (migration renames, JS method renames, EF version bumps, SQL patterns) into a distinct PR focused on the scoped services objective.
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective: configuring the Besql dbContext to resolve scoped services, which is achieved by replacing PooledDbContextFactory with IDbContextFactory.
Linked Issues check ✅ Passed The PR successfully replaces PooledDbContextFactory with IDbContextFactory across DbContextFactoryBase [#11775] and BesqlDbContextFactory [#11775], enabling scoped service resolution as required.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/Besql/Bit.Besql/wwwroot/bit-besql.js (1)

20-23: Remove invalid status property from Blob options.

The status: 200 property is not a valid option for the Blob constructor. The Blob constructor only accepts type and endings options. This property is silently ignored but represents dead code.

     const blob = new Blob([data], {
-        type: 'application/octet-stream',
-        status: 200
+        type: 'application/octet-stream'
     });
src/Besql/Bit.Besql/DbContextFactoryBase.cs (1)

17-29: Race condition in initialization check.

The check if (dbContextInitializerTcs is null) followed by await StartRunningDbContextInitializer() is not thread-safe. Multiple concurrent calls to CreateDbContextAsync could both see null and attempt to start initialization.

Consider using Interlocked.CompareExchange or a lock to ensure single initialization:

+private readonly object _initLock = new();
 private TaskCompletionSource? dbContextInitializerTcs;

 [RequiresUnreferencedCode("Calls StartRunningDbContextInitializer()")]
 public virtual async Task<TDbContext> CreateDbContextAsync(CancellationToken cancellationToken = default)
 {
-    if (dbContextInitializerTcs is null)
-    {
-        await StartRunningDbContextInitializer();
-    }
+    if (dbContextInitializerTcs is null)
+    {
+        lock (_initLock)
+        {
+            if (dbContextInitializerTcs is null)
+            {
+                _ = StartRunningDbContextInitializerLocked();
+            }
+        }
+    }

     await dbContextInitializerTcs!.Task.ConfigureAwait(false);

Alternatively, use Lazy<Task> for thread-safe lazy initialization.

♻️ Duplicate comments (1)
src/Besql/Bit.Besql/DbContextFactoryBase.cs (1)

36-53: Race condition in StartRunningDbContextInitializer.

This method has the same race condition issue - multiple threads could pass the if (dbContextInitializerTcs is not null) check before any of them assigns the TaskCompletionSource at line 42. This would result in multiple initialization attempts.

This is covered by the fix suggested above for CreateDbContextAsync.

🧹 Nitpick comments (3)
src/Besql/Bit.Besql/wwwroot/bit-besql.js (2)

4-4: Consider aligning internal function name with property name.

The named function expression besqlPersist differs from its assigned property name persist. While named function expressions help with debugging, consistent naming improves maintainability.

-BitBesql.persist = async function besqlPersist(fileName) {
+BitBesql.persist = async function persist(fileName) {

36-36: Consider aligning internal function name with property name.

Same naming inconsistency as persist above.

-BitBesql.load = async function besqlLoad(fileName) {
+BitBesql.load = async function load(fileName) {
src/Besql/Bit.Besql/BesqlDbContextFactory.cs (1)

43-48: Empty catch block silently swallows exceptions.

The empty catch block hides potential issues with LazyAssemblyLoader. Consider logging the exception or at least adding a comment explaining why all exceptions are intentionally ignored.

         try
         {
             await using var scope = _serviceProvider.CreateAsyncScope();
             await scope.ServiceProvider.GetRequiredService<LazyAssemblyLoader>().LoadAssembliesAsync(["System.Private.Xml.wasm"]);
         }
-        catch { }
+        catch (Exception)
+        {
+            // LazyAssemblyLoader may not be available in all hosting scenarios (e.g., server-side).
+            // Failures are non-fatal as the assembly may already be loaded or not required.
+        }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 946e926 and 05c8cdb.

📒 Files selected for processing (13)
  • src/Besql/Bit.Besql/BesqlDbContextFactory.cs (1 hunks)
  • src/Besql/Bit.Besql/BesqlDbContextInterceptor.cs (1 hunks)
  • src/Besql/Bit.Besql/Bit.Besql.csproj (1 hunks)
  • src/Besql/Bit.Besql/DbContextFactoryBase.cs (3 hunks)
  • src/Besql/Bit.Besql/IServiceCollectionBesqlExtentions.cs (2 hunks)
  • src/Besql/Bit.Besql/wwwroot/bit-besql.js (2 hunks)
  • src/Besql/Demo/Bit.Besql.Demo.Client/Data/CompiledModel/OfflineDbContextModelBuilder.cs (2 hunks)
  • src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/20240105010046_InitialMigration.Designer.cs (0 hunks)
  • src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/20251130123559_Initial.Designer.cs (1 hunks)
  • src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/20251130123559_Initial.cs (1 hunks)
  • src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/OfflineDbContextModelSnapshot.cs (1 hunks)
  • src/Besql/Demo/Bit.Besql.Demo.Client/Extensions/ServiceCollectionExtensions.cs (1 hunks)
  • src/Besql/Demo/Bit.Besql.Demo/Bit.Besql.Demo.csproj (0 hunks)
💤 Files with no reviewable changes (2)
  • src/Besql/Demo/Bit.Besql.Demo/Bit.Besql.Demo.csproj
  • src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/20240105010046_InitialMigration.Designer.cs
🧰 Additional context used
🧬 Code graph analysis (6)
src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/20251130123559_Initial.Designer.cs (3)
src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/OfflineDbContextModelSnapshot.cs (1)
  • DbContext (11-66)
src/Besql/Demo/Bit.Besql.Demo.Client/Data/OfflineDbContext.cs (1)
  • OfflineDbContext (7-25)
src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/20251130123559_Initial.cs (1)
  • Initial (10-52)
src/Besql/Demo/Bit.Besql.Demo.Client/Extensions/ServiceCollectionExtensions.cs (1)
src/Besql/Demo/Bit.Besql.Demo.Client/Data/CompiledModel/OfflineDbContextModelBuilder.cs (2)
  • OfflineDbContextModel (11-26)
  • OfflineDbContextModel (13-16)
src/Besql/Bit.Besql/BesqlDbContextFactory.cs (1)
src/Besql/Bit.Besql/DbContextFactoryBase.cs (2)
  • TDbContext (31-34)
  • DbContextFactoryBase (8-64)
src/Besql/Bit.Besql/IServiceCollectionBesqlExtentions.cs (4)
src/Besql/Bit.Besql/BesqlDbContextFactory.cs (3)
  • TDbContext (58-61)
  • BesqlDbContextFactory (11-62)
  • BesqlDbContextFactory (19-38)
src/Besql/Bit.Besql/DbContextFactoryBase.cs (2)
  • TDbContext (31-34)
  • DbContextFactoryBase (8-64)
src/Besql/Bit.Besql/BitBesqlNoopStoage.cs (4)
  • Task (8-11)
  • Task (13-16)
  • Task (22-25)
  • BitBesqlNoopStoage (6-26)
src/Besql/Bit.Besql/IBitBesqlStorage.cs (3)
  • Task (11-11)
  • Task (18-18)
  • Task (35-35)
src/Besql/Bit.Besql/DbContextFactoryBase.cs (1)
src/Besql/Bit.Besql/BesqlDbContextFactory.cs (2)
  • TDbContext (58-61)
  • RequiresUnreferencedCode (40-56)
src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/OfflineDbContextModelSnapshot.cs (2)
src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/20251130123559_Initial.Designer.cs (1)
  • DbContext (12-69)
src/Besql/Demo/Bit.Besql.Demo.Client/Data/OfflineDbContext.cs (1)
  • OfflineDbContext (7-25)
🪛 GitHub Check: build Bit.Besql
src/Besql/Bit.Besql/DbContextFactoryBase.cs

[warning] 17-17:
Member 'Bit.Besql.DbContextFactoryBase.CreateDbContextAsync(CancellationToken)' with 'RequiresUnreferencedCodeAttribute' implements interface member 'Microsoft.EntityFrameworkCore.IDbContextFactory.CreateDbContextAsync(CancellationToken)' without 'RequiresUnreferencedCodeAttribute'. 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides.


[warning] 17-17:
Member 'Bit.Besql.DbContextFactoryBase.CreateDbContextAsync(CancellationToken)' with 'RequiresUnreferencedCodeAttribute' implements interface member 'Microsoft.EntityFrameworkCore.IDbContextFactory.CreateDbContextAsync(CancellationToken)' without 'RequiresUnreferencedCodeAttribute'. 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides.


[warning] 17-17:
Member 'Bit.Besql.DbContextFactoryBase.CreateDbContextAsync(CancellationToken)' with 'RequiresUnreferencedCodeAttribute' implements interface member 'Microsoft.EntityFrameworkCore.IDbContextFactory.CreateDbContextAsync(CancellationToken)' without 'RequiresUnreferencedCodeAttribute'. 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides.

🔇 Additional comments (14)
src/Besql/Bit.Besql/BesqlDbContextInterceptor.cs (1)

10-10: Improved SQL keyword detection with trailing spaces.

Good change. Adding trailing spaces to the keywords prevents false positives (e.g., matching "UPDATING" as "UPDATE"). The patterns correctly match standard SQL statement prefixes.

src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/OfflineDbContextModelSnapshot.cs (1)

1-66: Auto-generated EF Core model snapshot.

This is auto-generated code from EF Core migrations tooling. The ProductVersion update to 10.0.0 is consistent with the broader EF Core version alignment in this PR.

src/Besql/Demo/Bit.Besql.Demo.Client/Data/CompiledModel/OfflineDbContextModelBuilder.cs (1)

1-26: Auto-generated EF Core compiled model.

This is auto-generated code from EF Core compiled model tooling. The updated modelId and ProductVersion 10.0.0 are expected artifacts of model regeneration.

src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/20251130123559_Initial.cs (1)

10-10: Migration class renamed to follow EF Core conventions.

The rename from InitialMigration to Initial aligns with the migration identifier in the designer file ([Migration("20251130123559_Initial")]). The migration logic for creating the WeatherForecasts table and seeding data is correct.

src/Besql/Bit.Besql/Bit.Besql.csproj (1)

8-8: Document why EF1001 suppression is necessary.

Suppressing EF1001 indicates the DbContextFactoryBase implementation relies on internal Entity Framework Core APIs that may change or be removed in future versions without notice. Add comments to the implementation explaining which internal APIs are used and why public alternatives aren't viable, so maintainers understand the compatibility risk and can address it during EF Core upgrades.

src/Besql/Demo/Bit.Besql.Demo.Client/Extensions/ServiceCollectionExtensions.cs (1)

10-15: LGTM!

The fully-qualified path for OfflineDbContextModel.Instance is explicit and avoids potential namespace conflicts. The DbContext configuration correctly wires up the compiled model and migration initializer.

src/Besql/Demo/Bit.Besql.Demo.Client/Data/Migrations/20251130123559_Initial.Designer.cs (1)

1-69: LGTM!

This is a standard auto-generated EF Core migration designer file. The model configuration and seed data are consistent with the corresponding migration and snapshot files.

src/Besql/Bit.Besql/IServiceCollectionBesqlExtentions.cs (3)

17-20: LGTM: Lifetime parameter enables scoped service resolution.

The new ServiceLifetime parameter with a Singleton default maintains backward compatibility while enabling the PR's objective of supporting scoped services when needed.


53-59: Non-browser path correctly updated.

The non-browser path now uses DbContextFactoryBase<TDbContext> instead of a pooled factory, enabling scoped service resolution consistently across both browser and non-browser scenarios.


41-48: Verify the factory type is correctly resolved by DI.

The change from BesqlPooledDbContextFactory<TDbContext> to BesqlDbContextFactory<TDbContext> needs confirmation that DbContextFactoryBase<TDbContext> properly declares IDbContextFactorySource<TDbContext> as a constructor dependency and that EF Core's AddDbContextFactory provides this service during resolution.

src/Besql/Bit.Besql/BesqlDbContextFactory.cs (2)

19-24: Constructor signature change aligns with the new factory pattern.

The reordered parameters and addition of IDbContextFactorySource<TDbContext> enable the factory to create DbContext instances through the DI-aware factory source rather than a pool, supporting the PR's goal of resolving scoped services.


58-61: Intentional restriction on synchronous CreateDbContext.

The NotSupportedException enforces async-first usage, which is appropriate given the async initialization requirements (storage loading, assembly loading). The error message clearly guides users to use CreateDbContextAsync.

src/Besql/Bit.Besql/DbContextFactoryBase.cs (2)

55-63: LGTM!

The initialization pattern correctly creates a temporary context, runs the initializer delegate, and disposes it. Using dbContext.GetService<IServiceProvider>() appropriately provides access to the scoped service provider.


3-3: Using internal EF Core API without version constraint.

IDbContextFactorySource<TDbContext> from Microsoft.EntityFrameworkCore.Internal is not part of the public API surface and may change between EF Core versions. Verify this type is available in your target EF Core version and document the minimum required version in your project file or configuration comments.

@ysmoradi ysmoradi merged commit d62044e into bitfoundation:develop Nov 30, 2025
3 checks passed
@ysmoradi ysmoradi deleted the 11775 branch November 30, 2025 14:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bit Besql dbContext must be able to resolve scoped services

1 participant