// Auto-generated by create-backlist — DO NOT EDIT MANUALLY
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using <%= projectName %>.Models;
namespace <%= projectName %>.Data
{
///
/// Main EF Core DbContext for <%= projectName %>.
/// Includes: soft-delete global filter, automatic audit timestamps,
/// unique indexes, and seed-data scaffolding hooks.
///
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions options)
: base(options) { }
// ── DbSets ────────────────────────────────────────────────────────────
<% modelsToGenerate.forEach(model => { %>
/// Represents the <%= model.name %> table.
public DbSet<<%= model.name %>> <%= model.name %>s { get; set; }
<% }); %>
// ── Model Configuration ───────────────────────────────────────────────
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
<% modelsToGenerate.forEach(model => { %>
// ── <%= model.name %> ──────────────────────────────────────────────
modelBuilder.Entity<<%= model.name %>>(entity =>
{
entity.HasKey(e => e.Id);
// Soft-delete: only return rows where DeletedAt is null
entity.HasQueryFilter(e => e.DeletedAt == null);
// Unique indexes
<% (model.fields || []).forEach(field => {
if (field.isUnique) { %>
entity.HasIndex(e => e.<%= field.name.charAt(0).toUpperCase() + field.name.slice(1) %>)
.IsUnique()
.HasDatabaseName("IX_<%= model.name %>_<%= field.name.charAt(0).toUpperCase() + field.name.slice(1) %>");
<% } }); %>
// Column precision for decimal fields
<% (model.fields || []).forEach(field => {
const n = String(field.name || '').toLowerCase();
const isDecimal = field.type === 'Number' && (n.includes('price') || n.includes('amount') || n.includes('total') || n.includes('cost'));
if (isDecimal) { %>
entity.Property(e => e.<%= field.name.charAt(0).toUpperCase() + field.name.slice(1) %>)
.HasColumnType("decimal(18,2)");
<% } }); %>
// Audit timestamp defaults
entity.Property(e => e.CreatedAt).HasDefaultValueSql("NOW()");
entity.Property(e => e.UpdatedAt).HasDefaultValueSql("NOW()");
// Table name override (snake_case convention)
entity.ToTable("<%= model.name.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '') %>s");
});
<% }); %>
}
// ── Automatic Audit: SaveChanges / SaveChangesAsync ───────────────────
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
ApplyAuditInfo();
return base.SaveChanges(acceptAllChangesOnSuccess);
}
public override Task SaveChangesAsync(
bool acceptAllChangesOnSuccess,
CancellationToken cancellationToken = default)
{
ApplyAuditInfo();
return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
private void ApplyAuditInfo()
{
var now = DateTime.UtcNow;
foreach (EntityEntry entry in ChangeTracker.Entries())
{
if (entry.State == EntityState.Added)
{
if (entry.Properties.Any(p => p.Metadata.Name == "CreatedAt"))
entry.Property("CreatedAt").CurrentValue = now;
if (entry.Properties.Any(p => p.Metadata.Name == "UpdatedAt"))
entry.Property("UpdatedAt").CurrentValue = now;
}
else if (entry.State == EntityState.Modified)
{
if (entry.Properties.Any(p => p.Metadata.Name == "UpdatedAt"))
entry.Property("UpdatedAt").CurrentValue = now;
// Prevent CreatedAt from being overwritten on update
if (entry.Properties.Any(p => p.Metadata.Name == "CreatedAt"))
entry.Property("CreatedAt").IsModified = false;
}
}
}
}
}