Skip to content

Getting Started with Entity Framework Core

Arc provides two approaches for integrating Entity Framework Core into your application:

  1. Builder Pattern (WithEntityFrameworkCore) - Recommended when using Arc’s IArcBuilder with full auto-discovery and observation support
  2. Direct Registration - Flexible approach that works independently of Arc

When using Arc’s application framework, the WithEntityFrameworkCore() extension method provides the most streamlined setup with automatic DbContext discovery and observation support.

builder.AddCratisArc(configureBuilder: arcBuilder =>
{
arcBuilder.WithEntityFrameworkCore(options =>
{
options.ConnectionString = "Server=localhost;Database=MyDb;Trusted_Connection=true";
});
});

This single configuration:

  • Automatically discovers all DbContext types inheriting from BaseDbContext or ReadOnlyDbContext
  • Registers them with the connection string using appropriate patterns (read-only vs read-write)
  • Enables observation support for real-time change notifications
  • Applies all Arc conventions (ConceptAs support, entity mapping, etc.)

The EntityFrameworkCoreOptions class provides the following configuration:

PropertyTypeDefaultDescription
ConnectionStringstring""The database connection string. Required for auto-discovery.
AutoDiscoverDbContextsbooltrueWhether to automatically discover and register DbContext types.
JsonConvertersIList<JsonConverter>[]Additional System.Text.Json converters merged into JsonConversionOptions at startup. Use this to handle interface-typed or abstract [Json] properties. See JSON Conversion.

When AutoDiscoverDbContexts is enabled (default), the framework automatically:

  1. Scans for all types inheriting from BaseDbContext
  2. Identifies which ones are ReadOnlyDbContext subtypes
  3. Registers read-only contexts with AddReadOnlyDbContextWithConnectionString
  4. Registers read-write contexts with AddDbContextWithConnectionString
  5. Excludes any types marked with [IgnoreAutoRegistration]
// Your DbContext types - automatically discovered and registered
public class OrdersDbContext : BaseDbContext
{
public OrdersDbContext(DbContextOptions<OrdersDbContext> options) : base(options) { }
public DbSet<Order> Orders { get; set; }
}
public class ReportingDbContext : ReadOnlyDbContext
{
public ReportingDbContext(DbContextOptions<ReportingDbContext> options) : base(options) { }
public DbSet<OrderSummary> OrderSummaries { get; set; }
}

If you need manual control over DbContext registration, disable auto-discovery:

builder.AddCratisArc(configureBuilder: arcBuilder =>
{
arcBuilder.WithEntityFrameworkCore(
configureOptions: options =>
{
options.ConnectionString = "Server=localhost;Database=MyDb;Trusted_Connection=true";
options.AutoDiscoverDbContexts = false;
},
configureEfCore: efBuilder =>
{
// Manual registration with custom options
efBuilder.AddDbContext<OrdersDbContext>((sp, opts) =>
{
opts.EnableSensitiveDataLogging();
});
});
});

The IEntityFrameworkCoreBuilder provides methods for manual DbContext registration:

arcBuilder.WithEntityFrameworkCore(
configureOptions: options =>
{
options.ConnectionString = "Server=localhost;Database=MyDb;Trusted_Connection=true";
options.AutoDiscoverDbContexts = false;
},
configureEfCore: efBuilder =>
{
// Use connection string from options
efBuilder.AddDbContext<OrdersDbContext>();
// Or specify a different connection string
efBuilder.AddDbContext<ArchiveDbContext>("Server=archive;Database=Archive;Trusted_Connection=true");
});

Use the [IgnoreAutoRegistration] attribute to exclude specific DbContext types:

[IgnoreAutoRegistration]
public class TestDbContext : BaseDbContext
{
// This context won't be auto-registered
}

If you’re not using Arc’s builder pattern or need more flexibility, you can register Entity Framework Core support directly on IServiceCollection. This approach doesn’t require the full Arc framework.

// Add observation services (optional, but recommended)
services.AddEntityFrameworkCoreObservation();
// Register your DbContext with connection string
services.AddDbContextWithConnectionString<OrdersDbContext>(
"Server=localhost;Database=MyDb;Trusted_Connection=true");
services.AddDbContextWithConnectionString<OrdersDbContext>(
"Server=localhost;Database=MyDb;Trusted_Connection=true",
(serviceProvider, options) =>
{
options.EnableSensitiveDataLogging();
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
});
services.AddReadOnlyDbContextWithConnectionString<ReportingDbContext>(
"Server=localhost;Database=MyDb;Trusted_Connection=true");

For direct registration with assembly scanning:

// Discover and register all ReadOnlyDbContext types from assemblies
services.AddReadModelDbContextsWithConnectionStringFromAssemblies(
"Server=localhost;Database=MyDb;Trusted_Connection=true",
optionsAction: null,
typeof(Program).Assembly,
typeof(OrdersDbContext).Assembly);
FeatureBuilder PatternDirect Registration
Auto-discovery✅ Built-in⚠️ Assembly-based only
Observation support✅ Automatic⚠️ Manual setup required
Arc integration✅ Full❌ Not required
FlexibilityGoodMaximum
ConfigurationCentralizedDistributed

Use Builder Pattern when:

  • You’re using Arc’s IArcBuilder pattern
  • You want automatic DbContext discovery
  • You want observation support without extra configuration
  • You prefer centralized configuration

Use Direct Registration when:

  • You’re not using the full Arc framework
  • You need maximum flexibility in registration
  • You’re integrating with an existing application
  • You want fine-grained control over each DbContext

When using direct registration with observation support, ensure you register observation services before calling AddCratisArc():

// Register observation services first
services.AddEntityFrameworkCoreObservation();
// Then register your DbContexts
services.AddDbContextWithConnectionString<OrdersDbContext>(connectionString);
// Finally, add Arc
builder.AddCratisArc();

This ensures the singleton IEntityChangeTracker is properly shared across all interceptors.

Note: When using WithEntityFrameworkCore(), this ordering is handled automatically.