Database-first EF Core data layer for KoreForge applications.
KoreForge.Data provides scaffolded EF Core DbContext and entity classes generated from existing SQL Server databases. The library follows a database-first approach — the database schema is the source of truth, and all entity code is produced by dotnet ef dbcontext scaffold.
- Database-first — schema is authoritative; EF migrations are not used
- Generated code is disposable — scaffold output can be deleted and recreated at any time
- Custom code survives regeneration — extensions live in partial classes outside the Generated/ folder
- Scripts are the entry point — developers use PowerShell scripts, not raw CLI commands
- Lookup tables, not enums — reference data lives in database tables with FK relationships
| Package | NuGet |
|---|---|
KoreForge.Data |
KoreForge.Data/
├── config/
│ └── scaffold-config.json # Drives scaffolding — one entry per database
├── scripts/
│ ├── scaffold-db.ps1 # Config-driven scaffold runner
│ └── AlertsDB-Notification-Schema.sql # DDL for the Notification schema
├── src/KF.Data/
│ ├── AlertsDbContext.cs # Partial context extension (ns: KF.Data)
│ ├── AlertsDbOptions.cs # Connection options (ns: KF.Data)
│ ├── AlertsDbServiceCollectionExtensions.cs # DI registration (ns: KF.Data)
│ └── Generated/ # Scaffold output — DO NOT EDIT
│ └── Alerts/ # AlertsDB database
│ ├── AlertsDbContext.cs # Generated context (ns: KF.Data)
│ └── Notification/ # Notification schema entities
│ ├── Channel.cs # (ns: KF.Data.Alerts.Notification)
│ ├── Priority.cs
│ ├── OutboxStatus.cs
│ ├── SendOutcome.cs
│ ├── NotificationOutbox.cs
│ ├── EmailPayload.cs
│ └── SmsPayload.cs
├── tst/KF.Data.Tests/
├── scr/ # Build & release scripts
├── doc/ # Documentation
└── artifacts/ # NuGet package output
dotnet add package KoreForge.Datausing KF.Data;
builder.Services.AddAlertsDb(opts =>
opts.ConnectionString = builder.Configuration.GetConnectionString("AlertsDB")!);Or with a raw connection string:
builder.Services.AddAlertsDb("Server=.;Database=AlertsDB;...";using KF.Data.Alerts.Notification;
public class NotificationService(AlertsDbContext db)
{
public async Task<List<NotificationOutbox>> GetPendingAsync(CancellationToken ct)
{
var pendingStatus = await db.OutboxStatus
.SingleAsync(s => s.Name == "Pending", ct);
return await db.NotificationOutbox
.Include(n => n.Channel)
.Include(n => n.Priority)
.Where(n => n.OutboxStatusId == pendingStatus.OutboxStatusId)
.OrderBy(n => n.CreatedAt)
.ToListAsync(ct);
}
}| Table | Purpose |
|---|---|
Channel |
Lookup: Email, SMS, Push, InApp |
Priority |
Lookup: Low, Normal, High, Critical |
OutboxStatus |
Lookup: Pending, Processing, Sent, Failed, Cancelled |
SendOutcome |
Lookup: Success, HardBounce, SoftBounce, Rejected, Timeout, ProviderError |
NotificationOutbox |
Core outbox table with FK to all lookups |
EmailPayload |
Email-specific fields (from, cc, bcc, html flag) |
SmsPayload |
SMS-specific fields (from number, provider message id) |
All lookup values are database rows — no C# enums. FK relationships provide navigation properties automatically via scaffold.
- .NET 10 SDK
- SQL Server instance with the target database
- Run
dotnet tool restoreonce to installdotnet-ef
.\scripts\scaffold-db.ps1This reads config/scaffold-config.json, cleans existing generated output, and runs dotnet ef dbcontext scaffold for each configured database.
To scaffold a single database:
.\scripts\scaffold-db.ps1 -Database AlertsDB- Run the SQL DDL against the target server
- Add a new entry to
config/scaffold-config.json - Run
.\scripts\scaffold-db.ps1 -Database NewDbName - Add options class, DI registration, and empty partial context at
src/KF.Data/project root - Set
namespaceandcontextNamespacein the config to keep "Generated" out of namespaces
Generated files live in Generated/ and must never be edited by hand. To add custom behaviour, create partial classes at the project root (or any folder outside Generated/):
// src/KF.Data/NotificationOutboxExtensions.cs
namespace KF.Data.Alerts.Notification;
public partial class NotificationOutbox
{
public bool IsOverdue => OutboxStatus?.Name == "Pending"
&& CreatedAt < DateTimeOffset.UtcNow.AddHours(-1);
}An empty partial AlertsDbContext is provided at src/KF.Data/AlertsDbContext.cs for context-level extensions.
| Item | Namespace | Example |
|---|---|---|
| DbContext, Options, DI | {RootNs} |
KF.Data |
| Entity models | {RootNs}.{DbName}.{Schema} |
KF.Data.Alerts.Notification |
| Entity models (dbo schema) | {RootNs}.{DbName} |
KF.Data.Alerts |
"Generated" never appears in a namespace — it is purely a folder for scaffold output.
| Script | Purpose |
|---|---|
scripts/scaffold-db.ps1 |
Config-driven scaffold runner |
scr/build-clean.ps1 |
Clean build outputs |
scr/build-rebuild.ps1 |
Force rebuild |
scr/build-test.ps1 |
Build + run tests |
scr/build-test-codecoverage.ps1 |
Build + test + coverage report |
scr/git-push.ps1 |
Add, commit, push |
scr/git-push-nuget.ps1 |
Tag and push for NuGet release |