Automatic database hookup
Out of the box we support the following databases:
- Sqlite
- PostgreSQL
- Microsoft SQL Server
The examples below are registration or service fragments for an existing host; supply the named contexts and import Cratis.Arc.EntityFrameworkCore, Microsoft.EntityFrameworkCore, and Microsoft.Extensions.DependencyInjection. Contexts must forward their options to their base constructor. Start with getting started for the optional package and Arc setup.
Database hookup selects a provider; it does not apply migrations. SQLite strings use Data Source=store.db; PostgreSQL detection requires Host= and Database=; SQL Server detection looks for server/data-source and SQL Server-specific keywords. Unrecognized strings throw UnsupportedDatabaseType.
You can use the standard EF Core method with the Arc database detection extension:
services.AddDbContext<MyDbContext>(opt => opt.UseDatabaseFromConnectionString("Data Source=store.db"));Note: From the connection string it will do the correct
.UseSqlite(),.UseNpgsql()or.UseSqlServer()call on the builder.
However, it is recommended to use the Arc registration methods which use the pooled factory pattern for better performance and to support multiple database providers:
services.AddDbContextWithConnectionString<MyDbContext>("Data Source=store.db", (serviceProvider, opt) => opt.EnableDetailedErrors());This method automatically:
- Uses
AddPooledDbContextFactoryfor improved performance - Applies all
BaseDbContextconfigurations (interceptors, service replacements) - Registers both the factory and a scoped DbContext instance
- Supports multiple database providers in the same application
Multiple Database Providers
Section titled “Multiple Database Providers”The Arc Entity Framework integration uses the pooled factory pattern (IDbContextFactory<T>) internally. Different context types can use different database providers. A single context’s options must select only one provider; this is not a prohibition on multiple providers anywhere in the application’s DI container.
The pooled factory approach provides:
- Multiple database provider support - Different contexts can use different databases (SQLite, SQL Server, PostgreSQL)
- Improved performance - DbContext instances are pooled and reused
- Reduced memory overhead - Internal service providers are shared across pooled instances
All registration methods automatically register both:
IDbContextFactory<TDbContext>- For creating DbContext instancesTDbContext- Scoped instance created from the factory
Using DbContext in Your Code
Section titled “Using DbContext in Your Code”You can inject DbContexts directly as you normally would:
public class MyService{ private readonly MyDbContext _context;
public MyService(MyDbContext context) { _context = context; }}Or you can use IDbContextFactory<T> when you need more control over the DbContext lifetime:
public class MyService{ private readonly IDbContextFactory<MyDbContext> _contextFactory;
public MyService(IDbContextFactory<MyDbContext> contextFactory) { _contextFactory = contextFactory; }
public async Task ProcessAsync() { await using var context = await _contextFactory.CreateDbContextAsync(); // Use context }}Important: Pooling reuses context instances and their options. These helpers capture the supplied connection string; they do not implement tenant-aware database selection. Do not capture request-scoped tenant state in pooled configuration. Test any application-supplied isolation strategy across pooled reuse.
Read Only DbContexts
Section titled “Read Only DbContexts”For any read-only DbContext there is also an extension method:
services.AddReadOnlyDbContextWithConnectionString<MyDbContext>("Data Source=store.db", (serviceProvider, opt) => opt.EnableDetailedErrors());Automatic Registration from Assemblies
Section titled “Automatic Registration from Assemblies”The framework provides methods to automatically discover and register all ReadOnlyDbContext types from specified assemblies:
// Register all ReadOnlyDbContext types from assemblies with a common options actionservices.AddReadModelDbContextsFromAssemblies((serviceProvider, opt) => opt.UseDatabaseFromConnectionString(connectionString), assembly1, assembly2);
// Register all ReadOnlyDbContext types from assemblies with a connection stringservices.AddReadModelDbContextsWithConnectionStringFromAssemblies(connectionString, (serviceProvider, opt) => { /* additional options */ }, assembly1, assembly2);Registration Filtering Rules
Section titled “Registration Filtering Rules”When using automatic registration, the framework applies the following filtering rules:
-
Public Classes Only: Only
publicDbContext classes will be automatically registered. Internal, private, or protected classes are ignored. -
Assembly Membership: Only DbContext classes that belong to the specified assemblies will be considered for registration.
-
Attribute-Based Exclusion: Classes marked with the
IgnoreAutoRegistrationAttributewill be excluded from automatic registration.
Excluding DbContexts from Automatic Registration
Section titled “Excluding DbContexts from Automatic Registration”If you have a DbContext that should not be automatically registered (for example, if it requires special configuration or should be registered manually), you can exclude it using the IgnoreAutoRegistrationAttribute:
using Cratis.Arc;using Cratis.Arc.EntityFrameworkCore;using Microsoft.EntityFrameworkCore;
[IgnoreAutoRegistration]public class SpecialDbContext(DbContextOptions<SpecialDbContext> options) : ReadOnlyDbContext(options){}This is useful for scenarios where:
- The DbContext requires special configuration
- You want to register it with different lifetime scopes
- It’s used only in specific conditions
- You want to register it manually with custom options