diff --git a/DataArc.EntityFrameworkCore.Demo.Benchmark/DataArc.EntityFrameworkCore.Demo.Benchmark.csproj b/DataArc.EntityFrameworkCore.Demo.Benchmark/DataArc.EntityFrameworkCore.Demo.Benchmark.csproj
index 58af83b..9a1a3e9 100644
--- a/DataArc.EntityFrameworkCore.Demo.Benchmark/DataArc.EntityFrameworkCore.Demo.Benchmark.csproj
+++ b/DataArc.EntityFrameworkCore.Demo.Benchmark/DataArc.EntityFrameworkCore.Demo.Benchmark.csproj
@@ -22,4 +22,10 @@
+
+
+ Always
+
+
+
\ No newline at end of file
diff --git a/DataArc.EntityFrameworkCore.Demo.Benchmark/ProcessEmployeeFinanceDataBenchmark.cs b/DataArc.EntityFrameworkCore.Demo.Benchmark/ProcessEmployeeFinanceDataBenchmark.cs
index 6cdb3b8..2564578 100644
--- a/DataArc.EntityFrameworkCore.Demo.Benchmark/ProcessEmployeeFinanceDataBenchmark.cs
+++ b/DataArc.EntityFrameworkCore.Demo.Benchmark/ProcessEmployeeFinanceDataBenchmark.cs
@@ -11,9 +11,10 @@
using DataArc.Core;
using DataArc.EntityFrameworkCore.Demo.Persistence;
using DataArc.EntityFrameworkCore.Demo.Persistence.Database.Creator;
-using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBContexts;
using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBModels;
using DataArc.EntityFrameworkCore.Demo.Persistence.Utils;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Contracts;
+using Microsoft.Extensions.Configuration;
namespace DataArc.EntityFrameworkCore.Demo.Benchmark
{
@@ -38,14 +39,19 @@ public class RawEmployeeBulkDataBenchmark
[Params(62_500, 125_000, 250_000)]
public int RecordCount { get; set; }
- [Params(62_500)]
- public int BulkBatchSize { get; set; }
+ //[Params(62_500)]
+ public int BulkBatchSize => MaxRecordCount;
[GlobalSetup]
public void GlobalSetup()
{
+ var configurationManager = new ConfigurationManager();
+ configurationManager
+ .AddJsonFile("appsettings.json", optional: false)
+ .Build();
+
_serviceProvider = new ServiceCollection()
- .AddPersistence()
+ .AddPersistence(configurationManager)
.BuildServiceProvider();
_databaseCreators =
diff --git a/DataArc.EntityFrameworkCore.Demo.Benchmark/appsettings.json b/DataArc.EntityFrameworkCore.Demo.Benchmark/appsettings.json
new file mode 100644
index 0000000..1f25904
--- /dev/null
+++ b/DataArc.EntityFrameworkCore.Demo.Benchmark/appsettings.json
@@ -0,0 +1,8 @@
+{
+ "ConnectionStrings": {
+ "FinanceDb": "Server=.;Database=FinanceDb;Integrated Security=true;TrustServerCertificate=True;",
+ "HrDb": "Server=.;Database=HrDb;Integrated Security=true;TrustServerCertificate=True;",
+ "ItDb": "Server=.;Database=ItDb;Integrated Security=true;TrustServerCertificate=True;",
+ "OperationsDb": "Server=.;Database=OperationsDb;Integrated Security=true;TrustServerCertificate=True;"
+ }
+}
\ No newline at end of file
diff --git a/DataArc.EntityFrameworkCore.Demo.Persistence/Contracts/IFinanceDbContext.cs b/DataArc.EntityFrameworkCore.Demo.Persistence/Contracts/IFinanceDbContext.cs
new file mode 100644
index 0000000..1cd0652
--- /dev/null
+++ b/DataArc.EntityFrameworkCore.Demo.Persistence/Contracts/IFinanceDbContext.cs
@@ -0,0 +1,12 @@
+using DataArc.Core;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBModels;
+using Microsoft.EntityFrameworkCore;
+
+namespace DataArc.EntityFrameworkCore.Demo.Persistence.Contracts
+{
+ public interface IFinanceDbContext : IExecutionContext
+ {
+ DbSet? Employer { get; set; }
+ DbSet? Employee { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DataArc.EntityFrameworkCore.Demo.Persistence/Contracts/IHrDbContext.cs b/DataArc.EntityFrameworkCore.Demo.Persistence/Contracts/IHrDbContext.cs
new file mode 100644
index 0000000..272ae7d
--- /dev/null
+++ b/DataArc.EntityFrameworkCore.Demo.Persistence/Contracts/IHrDbContext.cs
@@ -0,0 +1,12 @@
+using DataArc.Core;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBModels;
+using Microsoft.EntityFrameworkCore;
+
+namespace DataArc.EntityFrameworkCore.Demo.Persistence.Contracts
+{
+ public interface IHrDbContext : IExecutionContext
+ {
+ DbSet? Employer { get; set; }
+ DbSet? Employee { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DataArc.EntityFrameworkCore.Demo.Persistence/Contracts/IItDbContext.cs b/DataArc.EntityFrameworkCore.Demo.Persistence/Contracts/IItDbContext.cs
new file mode 100644
index 0000000..02e2325
--- /dev/null
+++ b/DataArc.EntityFrameworkCore.Demo.Persistence/Contracts/IItDbContext.cs
@@ -0,0 +1,12 @@
+using DataArc.Core;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBModels;
+using Microsoft.EntityFrameworkCore;
+
+namespace DataArc.EntityFrameworkCore.Demo.Persistence.Contracts
+{
+ public interface IItDbContext : IExecutionContext
+ {
+ DbSet? Employer { get; set; }
+ DbSet? Employee { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DataArc.EntityFrameworkCore.Demo.Persistence/Contracts/IOperationsDbContext.cs b/DataArc.EntityFrameworkCore.Demo.Persistence/Contracts/IOperationsDbContext.cs
new file mode 100644
index 0000000..0a2777a
--- /dev/null
+++ b/DataArc.EntityFrameworkCore.Demo.Persistence/Contracts/IOperationsDbContext.cs
@@ -0,0 +1,12 @@
+using DataArc.Core;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBModels;
+using Microsoft.EntityFrameworkCore;
+
+namespace DataArc.EntityFrameworkCore.Demo.Persistence.Contracts
+{
+ public interface IOperationsDbContext : IExecutionContext
+ {
+ DbSet? Employer { get; set; }
+ DbSet? Employee { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/FinanceDbContext.cs b/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/FinanceDbContext.cs
index b1538a8..5a00d07 100644
--- a/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/FinanceDbContext.cs
+++ b/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/FinanceDbContext.cs
@@ -1,14 +1,9 @@
-using DataArc.Core;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Contracts;
using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBModels;
using Microsoft.EntityFrameworkCore;
namespace DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBContexts
{
- public interface IFinanceDbContext : IExecutionContext
- {
-
- }
-
internal class FinanceDbContext : DbContext, IFinanceDbContext
{
public FinanceDbContext(DbContextOptions dbContextOptions)
diff --git a/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/HrDbContext.cs b/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/HrDbContext.cs
index da4ef34..949686b 100644
--- a/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/HrDbContext.cs
+++ b/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/HrDbContext.cs
@@ -1,13 +1,9 @@
-using DataArc.Core;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Contracts;
using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBModels;
using Microsoft.EntityFrameworkCore;
namespace DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBContexts
{
- public interface IHrDbContext : IExecutionContext
- {
- }
-
internal class HrDbContext : DbContext, IHrDbContext
{
public HrDbContext(DbContextOptions dbContextOptions)
diff --git a/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/ItDbContext.cs b/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/ItDbContext.cs
index 2149cc5..f649366 100644
--- a/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/ItDbContext.cs
+++ b/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/ItDbContext.cs
@@ -1,16 +1,13 @@
-using DataArc.Core;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Contracts;
using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBModels;
using Microsoft.EntityFrameworkCore;
namespace DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBContexts
{
- public interface IItDbContext : IExecutionContext
- {
- }
-
internal class ItDbContext : DbContext, IItDbContext
{
- public ItDbContext(DbContextOptions dbContextOptions) : base(dbContextOptions) { }
+ public ItDbContext(DbContextOptions dbContextOptions)
+ : base(dbContextOptions) { }
public DbSet? Employer { get; set; }
public DbSet? Employee { get; set; }
diff --git a/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/OperationsDbContext.cs b/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/OperationsDbContext.cs
index 63d5e52..213c497 100644
--- a/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/OperationsDbContext.cs
+++ b/DataArc.EntityFrameworkCore.Demo.Persistence/Database/DBContexts/OperationsDbContext.cs
@@ -1,16 +1,13 @@
-using DataArc.Core;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Contracts;
using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBModels;
using Microsoft.EntityFrameworkCore;
namespace DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBContexts
{
- public interface IOperationsDbContext : IExecutionContext
- {
- }
-
internal class OperationsDbContext : DbContext, IOperationsDbContext
{
- public OperationsDbContext(DbContextOptions dbContextOptions) : base(dbContextOptions) { }
+ public OperationsDbContext(DbContextOptions dbContextOptions)
+ : base(dbContextOptions) { }
public DbSet? Employer { get; set; }
public DbSet? Employee { get; set; }
diff --git a/DataArc.EntityFrameworkCore.Demo.Persistence/PersistenceRegistration.cs b/DataArc.EntityFrameworkCore.Demo.Persistence/PersistenceRegistration.cs
index ce66ffb..a195951 100644
--- a/DataArc.EntityFrameworkCore.Demo.Persistence/PersistenceRegistration.cs
+++ b/DataArc.EntityFrameworkCore.Demo.Persistence/PersistenceRegistration.cs
@@ -1,13 +1,15 @@
-using DataArc.Core;
-using DataArc.EntityFrameworkCore.Demo.Persistence.Database.Creator;
-using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBContexts;
-using DataArc.EntityFrameworkCore.Demo.Persistence.Database.Seeder;
-using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
+using DataArc.Core;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Contracts;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Database.Creator;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBContexts;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Database.Seeder;
+
namespace DataArc.EntityFrameworkCore.Demo.Persistence
{
public static class PersistenceRegistration
@@ -17,12 +19,8 @@ public static class PersistenceRegistration
builder.AddConsole();
});
- public static IServiceCollection AddPersistence(this IServiceCollection services)
+ public static IServiceCollection AddPersistence(this IServiceCollection services, ConfigurationManager configurationManager)
{
- var configurationManager = new ConfigurationManager();
- configurationManager.AddJsonFile("appsettings.json", optional: false)
- .Build();
-
services
.AddDataArcCore()
.ConfigureDataArc(provider =>
diff --git a/DataArc.EntityFrameworkCore.Demo/Application/Modules/Finance/Features/SalaryAdjustments/Services/EmployeePerformanceService.cs b/DataArc.EntityFrameworkCore.Demo/Application/Modules/Finance/Features/SalaryAdjustments/Services/EmployeePerformanceService.cs
index 927ebcb..e55a29e 100644
--- a/DataArc.EntityFrameworkCore.Demo/Application/Modules/Finance/Features/SalaryAdjustments/Services/EmployeePerformanceService.cs
+++ b/DataArc.EntityFrameworkCore.Demo/Application/Modules/Finance/Features/SalaryAdjustments/Services/EmployeePerformanceService.cs
@@ -1,7 +1,7 @@
using DataArc.Core;
using DataArc.EntityFrameworkCore.Demo.Application.Modules.Finance.Features.SalaryAdjustments.Dtos;
-using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBContexts;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Contracts;
using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBModels;
namespace DataArc.EntityFrameworkCore.Demo.Application.Modules.Finance.Features.SalaryAdjustments.Services
diff --git a/DataArc.EntityFrameworkCore.Demo/Application/Modules/Finance/Features/SalaryAdjustments/Services/SalaryAdjustmentService.cs b/DataArc.EntityFrameworkCore.Demo/Application/Modules/Finance/Features/SalaryAdjustments/Services/SalaryAdjustmentService.cs
index 329fb4e..b22feb0 100644
--- a/DataArc.EntityFrameworkCore.Demo/Application/Modules/Finance/Features/SalaryAdjustments/Services/SalaryAdjustmentService.cs
+++ b/DataArc.EntityFrameworkCore.Demo/Application/Modules/Finance/Features/SalaryAdjustments/Services/SalaryAdjustmentService.cs
@@ -1,6 +1,5 @@
using DataArc.Core;
-
-using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBContexts;
+using DataArc.EntityFrameworkCore.Demo.Persistence.Contracts;
using DataArc.EntityFrameworkCore.Demo.Persistence.Database.DBModels;
namespace DataArc.EntityFrameworkCore.Demo.Application.Modules.Finance.Features.SalaryAdjustments.Services
diff --git a/DataArc.EntityFrameworkCore.Demo/Application/Modules/Finance/Registration/FinanceModuleRegistration.cs b/DataArc.EntityFrameworkCore.Demo/Application/Modules/Finance/Registration/FinanceModuleRegistration.cs
index f48c428..57637ec 100644
--- a/DataArc.EntityFrameworkCore.Demo/Application/Modules/Finance/Registration/FinanceModuleRegistration.cs
+++ b/DataArc.EntityFrameworkCore.Demo/Application/Modules/Finance/Registration/FinanceModuleRegistration.cs
@@ -1,15 +1,16 @@
using DataArc.EntityFrameworkCore.Demo.Application.Modules.Finance.Features.SalaryAdjustments.Services;
using DataArc.EntityFrameworkCore.Demo.Persistence;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace DataArc.EntityFrameworkCore.Demo.Application.Modules.Finance.Registration
{
public static class FinanceRegistrationModule
{
- public static IServiceCollection AddFinanceModule(this IServiceCollection services)
+ public static IServiceCollection AddFinanceModule(this IServiceCollection services, ConfigurationManager configurationManager)
{
// Register persistence layer for Finance module
- services.AddPersistence();
+ services.AddPersistence(configurationManager);
// Register Services
services.AddScoped();
services.AddScoped();
diff --git a/DataArc.EntityFrameworkCore.Demo/Program.cs b/DataArc.EntityFrameworkCore.Demo/Program.cs
index edf016f..56fb258 100644
--- a/DataArc.EntityFrameworkCore.Demo/Program.cs
+++ b/DataArc.EntityFrameworkCore.Demo/Program.cs
@@ -6,6 +6,7 @@
using DataArc.EntityFrameworkCore.Demo.Application.Workers;
using DataArc.EntityFrameworkCore.Demo.Persistence.Database.Creator;
using DataArc.EntityFrameworkCore.Demo.Persistence.Database.Seeder;
+using Microsoft.Extensions.Configuration;
const int batchSize = 100_000;
@@ -13,8 +14,13 @@
.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
+ var configurationManager = new ConfigurationManager();
+ configurationManager
+ .AddJsonFile("appsettings.json", optional: false)
+ .Build();
+
services
- .AddFinanceModule()
+ .AddFinanceModule(configurationManager)
.AddHostedService();
})
.Build();
diff --git a/README.md b/README.md
index 6a614de..a99f163 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
**DataArc.EntityFrameworkCore** uses EF Core.
-It provides a dedicated execution layer that helps application code coordinate serious EF Core data workflows across multiple `DbContext` boundaries without turning the workflow into scattered repository calls, handler classes, or manual `DbContext` plumbing.
+It provides a dedicated execution layer that helps application code coordinate serious EF Core data workflows across multiple `DbContext` boundaries without turning the workflow into scattered repository calls, handler classes, one-off bulk extensions, or manual `DbContext` plumbing.
This demo runs as a small .NET background worker.
@@ -47,6 +47,10 @@ Execute the workflow.
Receive structured results.
```
+A .NET `BackgroundService` gives the workflow a familiar home.
+
+DataArc.EntityFrameworkCore gives the workflow its execution model.
+
---
## Benchmark Snapshot
@@ -64,11 +68,11 @@ Each benchmark case inserts `RecordCount` employees into each participating cont
Total inserted records = RecordCount x 4
```
-| Method | Record Count Per Context | Bulk Batch Size | Total Inserted Records | Mean | StdDev | Allocated |
-|---|---:|---:|---:|---:|---:|---:|
-| ExecuteParallelBulkInsertAsync | 62,500 | 62,500 | 250,000 | 552.2 ms | 84.94 ms | 60.83 MB |
-| ExecuteParallelBulkInsertAsync | 125,000 | 62,500 | 500,000 | 818.4 ms | 90.35 ms | 121.19 MB |
-| ExecuteParallelBulkInsertAsync | 250,000 | 62,500 | 1,000,000 | 1,775.7 ms | 344.70 ms | 242.31 MB |
+| Method | Record Count Per Context | Total Inserted Records | Mean | StdDev | Completed Work Items | Lock Contentions | Gen0 | Allocated |
+|---|---:|---:|---:|---:|---:|---:|---:|---:|
+| ExecuteParallelBulkInsertAsync | 62,500 | 250,000 | 486.2 ms | 30.92 ms | 19,193 | - | 5,000 | 60.77 MB |
+| ExecuteParallelBulkInsertAsync | 125,000 | 500,000 | 887.7 ms | 159.61 ms | 38,051 | - | 10,000 | 120.93 MB |
+| ExecuteParallelBulkInsertAsync | 250,000 | 1,000,000 | 1,747.1 ms | 285.75 ms | 77,796 | - | 20,000 | 242.21 MB |
These results are workload-specific evidence, not a universal performance guarantee. Hardware, SQL Server configuration, schema shape, indexes, batch size, runtime version, and database state all affect results.
@@ -90,7 +94,11 @@ Many systems eventually need data workflows that move beyond one direct context
- bulk process scheduled jobs
- compose read models from more than one EF Core context
-DataArc.EntityFrameworkCore gives those workflows an explicit C# execution model.
+Plain EF Core does not provide native high-throughput bulk insert as a first-class API.
+
+Third-party bulk libraries can add bulk methods to a `DbContext`, although they do not provide a full execution pipeline across multiple EF Core context boundaries.
+
+DataArc.EntityFrameworkCore provides the coordination layer: command/query pipelines, explicit execution contexts, parallel execution, affected-record aggregation, failure handling, and structured results.
It is designed for EF Core work that needs:
@@ -137,6 +145,7 @@ The application flow:
9. Executes the command pipeline in parallel.
10. Queries top-rated employees across all four contexts.
11. Prints a short summary.
+12. Stops the host after the workflow completes.
```mermaid
flowchart LR
@@ -170,7 +179,7 @@ Program.cs = host setup + demo database preparation
DemoWorkflowWorker = background data workflow runner
SalaryAdjustmentService = read-transform-write workflow
EmployeePerformanceService = cross-context read model
-Persistence = EF Core contexts, registration, seeding, and database creators
+Persistence = EF Core contexts, contracts, registration, seeding, and database creators
```
This shape is familiar to .NET developers because many real data workflows run as background jobs, scheduled workers, import/export processors, reconciliation jobs, reporting projection builders, or internal batch processes.
@@ -180,10 +189,10 @@ const int batchSize = 100_000;
var host = Host
.CreateDefaultBuilder(args)
- .ConfigureServices(services =>
+ .ConfigureServices((context, services) =>
{
services
- .AddFinanceModule()
+ .AddFinanceModule(context.Configuration)
.AddHostedService();
})
.Build();
@@ -391,23 +400,24 @@ This creates one read model from multiple isolated EF Core contexts without expo
---
-## Internal DbContexts, Public Execution Boundaries
-
-The demo keeps concrete EF Core `DbContext` implementations internal to the persistence project.
+## Public Execution Contracts, Internal DbContexts
-Application code does not depend directly on `FinanceDbContext`, `HrDbContext`, `ItDbContext`, or `OperationsDbContext`.
+The demo exposes each EF Core boundary through a public execution-context contract.
-Instead, each EF Core boundary is exposed through a small public execution-context interface.
+Application code depends on these contracts, not on the concrete `DbContext` implementations.
-In DataArc, an execution context represents a logical boundary where work is performed. In this demo, each execution context is backed by an EF Core `DbContext`.
+The contracts define the DataArc execution boundaries and expose the EF Core sets available through those boundaries.
```csharp
public interface IFinanceDbContext : IExecutionContext
{
+ DbSet? Employer { get; set; }
+
+ DbSet? Employee { get; set; }
}
```
-The concrete context remains internal:
+The concrete `DbContext` implementation remains internal to the persistence project:
```csharp
internal class FinanceDbContext : DbContext, IFinanceDbContext
@@ -433,7 +443,7 @@ internal class FinanceDbContext : DbContext, IFinanceDbContext
}
```
-Application services route work through the public execution boundary:
+DataArc uses the public execution contract to route work to the registered EF Core implementation:
```csharp
commandBuilder
@@ -441,7 +451,7 @@ commandBuilder
.AddBulk(employees, batchSize);
```
-This keeps EF Core implementation details inside the persistence layer while still allowing application code to choose exactly where work executes.
+This keeps the concrete EF Core implementation hidden while giving the application a clear execution boundary to target.
---
@@ -449,6 +459,10 @@ This keeps EF Core implementation details inside the persistence layer while sti
Each EF Core context is registered as a DataArc database execution context.
+This demo uses SQL Server.
+
+The worker and application services do not configure SQL Server directly. They target DataArc execution contexts. SQL Server connection strings and EF Core provider configuration stay in `PersistenceRegistration.cs`.
+
```csharp
services.AddDataArcCore();
@@ -474,9 +488,9 @@ services.ConfigureDataArc(dataArc =>
The registration tells DataArc:
```text
-This interface is the execution boundary.
+This contract is the execution boundary.
This concrete DbContext is the EF Core implementation.
-This connection string points to the target database.
+This connection string points to the SQL Server database.
```
---
@@ -594,6 +608,11 @@ DataArc.EntityFrameworkCore.Demo
│ └── DemoWorkflowWorker.cs
│
├── Persistence
+│ ├── Contracts
+│ │ ├── IFinanceDbContext.cs
+│ │ ├── IHrDbContext.cs
+│ │ ├── IItDbContext.cs
+│ │ └── IOperationsDbContext.cs
│ ├── Database
│ │ ├── Creator
│ │ │ ├── FinanceDbCreator.cs
@@ -618,28 +637,37 @@ DataArc.EntityFrameworkCore.Demo
The application project owns the worker and use-case services.
-The persistence project owns EF Core contexts, database models, database creation, seeding, and DataArc registration.
+The persistence project owns EF Core contracts, contexts, database models, database creation, seeding, and DataArc registration.
----
+The demo application and benchmark project both reference the persistence project directly.
-## Running The Demo
+```text
+DataArc.EntityFrameworkCore.Demo
+ -> DataArc.EntityFrameworkCore.Demo.Persistence
-### 1. Configure Connection Strings
+DataArc.EntityFrameworkCore.Demo.Benchmark
+ -> DataArc.EntityFrameworkCore.Demo.Persistence
+```
-Update the SQL Server connection strings in `PersistenceRegistration.cs`.
+The benchmark references the persistence project directly so it measures the DataArc EF Core execution path without depending on the demo application shell.
-```csharp
-var financeConnectionString =
- "Server=YOUR_SERVER;Database=FinanceDb;Integrated Security=true;TrustServerCertificate=True;";
+---
-var hrConnectionString =
- "Server=YOUR_SERVER;Database=HrDb;Integrated Security=true;TrustServerCertificate=True;";
+## Running The Demo
-var itConnectionString =
- "Server=YOUR_SERVER;Database=ItDb;Integrated Security=true;TrustServerCertificate=True;";
+### 1. Configure Connection Strings
+
+Update the SQL Server connection strings in `appsettings.json`.
-var operationsConnectionString =
- "Server=YOUR_SERVER;Database=OperationsDb;Integrated Security=true;TrustServerCertificate=True;";
+```json
+{
+ "ConnectionStrings": {
+ "FinanceDb": "Server=YOUR_SERVER;Database=FinanceDb;Integrated Security=true;TrustServerCertificate=True;",
+ "HrDb": "Server=YOUR_SERVER;Database=HrDb;Integrated Security=true;TrustServerCertificate=True;",
+ "ItDb": "Server=YOUR_SERVER;Database=ItDb;Integrated Security=true;TrustServerCertificate=True;",
+ "OperationsDb": "Server=YOUR_SERVER;Database=OperationsDb;Integrated Security=true;TrustServerCertificate=True;"
+ }
+}
```
### 2. Run The Application
@@ -690,6 +718,8 @@ From the benchmark project:
dotnet run -c Release --framework net8.0
```
+The benchmark project has its own `appsettings.json` and references the persistence project directly.
+
Default benchmark shape:
```csharp
@@ -726,7 +756,7 @@ xychart-beta
title "Parallel bulk insert mean time"
x-axis ["250k", "500k", "1M"]
y-axis "Mean time in ms" 0 --> 2000
- bar [552.2, 818.4, 1775.7]
+ bar [486.2, 887.7, 1747.1]
```
```mermaid
@@ -734,7 +764,7 @@ xychart-beta
title "Managed memory allocated per operation"
x-axis ["250k", "500k", "1M"]
y-axis "Allocated MB" 0 --> 260
- bar [60.83, 121.19, 242.31]
+ bar [60.77, 120.93, 242.21]
```
---
@@ -781,8 +811,7 @@ DataArc.EntityFrameworkCore gives EF Core an explicit execution layer for high-t
It helps teams:
-- keep concrete `DbContext` implementations internal
-- expose public execution-context interfaces
+- define public execution contracts while keeping concrete `DbContext` implementations internal
- coordinate work across multiple EF Core contexts
- execute bulk command pipelines
- run parallel operations