Centeva.Auditing
5.0.0
Prefix Reserved
See the version list below for details.
dotnet add package Centeva.Auditing --version 5.0.0
NuGet\Install-Package Centeva.Auditing -Version 5.0.0
<PackageReference Include="Centeva.Auditing" Version="5.0.0" />
<PackageVersion Include="Centeva.Auditing" Version="5.0.0" />
<PackageReference Include="Centeva.Auditing" />
paket add Centeva.Auditing --version 5.0.0
#r "nuget: Centeva.Auditing, 5.0.0"
#:package Centeva.Auditing@5.0.0
#addin nuget:?package=Centeva.Auditing&version=5.0.0
#tool nuget:?package=Centeva.Auditing&version=5.0.0
Centeva.Auditing
This library provides audit entity models and Entity Framework Core configurations for SQL Server auditing. It is designed for use with EF Core (.NET 8, C# 12) and is intended to be ingested via NuGet by other applications.
Features
- Dual-Table Audit Schema: Separate
AuditandAuditDetailtables for normalized, performant audit logging. - Audit & AuditDetail Models: Standardized entities for audit logging with EF Core support.
- EntityTypeConfigurations: Fluent API configurations for
AuditandAuditDetailtables. - AuditIgnore Helpers: Utilities for ignoring tables, schemas, or columns during audit operations.
- AuditScriptCreator: Generates SQL scripts for audit triggers.
- AuditMigrationHelper: Automated tool for migrating from single-table to dual-table audit schema.
- Convention Support: Includes conventions for automatic trigger creation in EF Core.
BREAKING CHANGES in v5.0
Single-table audit logging has been removed. This library now exclusively uses a dual-table schema with separate Audit and AuditDetail tables.
Why Dual-Table?
The dual-table approach provides:
- Better Performance: Normalized schema reduces data duplication and improves query speed
- Flexibility: Easier to query operation-level or field-level changes independently
- Scalability: Optimized for large-scale audit databases (100M+ records)
Migration from v4.x (Single-Table to Dual-Table)
If you're upgrading from v4.x that used single-table auditing, you must migrate your existing audit data. The AuditMigrationHelper automates this process.
Prerequisites
- ⚠️ Create a full database backup before starting migration
- ⚠️ Plan for application downtime during the final swap phase
- Ensure you have sufficient database disk space (migration creates shadow tables)
Migration Process
Phase 1: Data Migration (No Downtime)
This phase migrates data to shadow tables while your application continues running:
using Centeva.Auditing.Helpers;
using Microsoft.Extensions.Logging;
var config = new AuditConfig(
schema: "dbo",
auditTable: "Audit",
auditDetailTable: "AuditDetail",
connectionString: "your-connection-string"
);
// Create logger (optional but recommended for progress tracking)
using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
var logger = loggerFactory.CreateLogger<Program>();
// Run migration (can take hours for large databases)
await AuditMigrationHelper.MigrateSingleToDualTable(
config,
logger: logger,
batchSize: 100_000 // Adjust based on your database size
);
Migration is resumable - if interrupted, you can re-run the same command to continue.
Phase 2: Table Swap (Requires Downtime)
After data migration completes, generate and execute the swap script during a maintenance window:
// Generate swap script
var scripts = await AuditMigrationHelper.GenerateMigrationScripts(config, logger);
// Save script to file for DBA review
File.WriteAllText("audit-table-swap.sql", scripts.SwapScript);
// Execute during maintenance window:
// 1. Stop application
// 2. Run the swap script in SQL Server Management Studio
// 3. Start application with updated trigger scripts
The swap script:
- Runs in a transaction (automatic rollback on failure)
- Includes pre-flight validation checks
- Takes ~30 seconds for most databases
- Transforms original
Audittable →AuditDetail - Renames
Audit_Migrationshadow table →Audit
Post-Migration Steps
- Regenerate audit triggers for dual-table schema:
using var creator = new AuditScriptCreator(config);
foreach (var script in creator.GetTriggerScripts())
{
// Execute against your database
}
- Update your DbContext to reference both tables:
public DbSet<AuditTable> Audit { get; set; }
public DbSet<AuditDetail> AuditDetail { get; set; }
- Remove single-table references from your codebase
Migration Safety Features
- ✅ Idempotent: Safe to re-run if interrupted
- ✅ Validation: Prevents running on already-migrated databases
- ✅ Transactional: Swap script uses transactions with automatic rollback
- ✅ Original Data Preserved: Source table unchanged during migration
- ✅ Progress Tracking: Detailed logging of migration progress
Rollback (If Needed)
If migration needs to be rolled back before the swap phase:
await AuditMigrationHelper.RollbackMigration(config, logger);
This removes shadow tables and re-enables audit triggers.
Audit Trigger Script Generation
Audit Logging
Summary audit data is logged to the Audit table, and field-level changes are logged to the AuditDetail table.
Configuring Auditing
using Centeva.Auditing.Helpers;
var config = new AuditConfig( schema: "dbo", auditTable: "Audit", auditDetailTable: "AuditDetail", connectionString: "your-connection-string" );
Generating Trigger Scripts
Use the AuditScriptCreator class to generate SQL scripts for audit triggers.
using Centeva.Auditing.Helpers;
var config = new AuditConfig( schema: "dbo", auditTable: "Audit", auditDetailTable: "AuditDetail", connectionString: "your-connection-string" );
using var creator = new AuditScriptCreator(config);
foreach (var script in creator.GetTriggerScripts(/* optional AuditIgnore rules */))
{
// Execute script against your database
}
Note: The
AuditScriptCreatorclass manages the connection lifecycle internally and implementsIDisposable. Always use ausingstatement or callDispose()when finished.
Getting Started (New Installations)
Note: If you're migrating from v4.x single-table schema, see the Migration from v4.x section above first.
1. Install the Package
Add the NuGet package to your project:
dotnet add package Centeva.Auditing
2. Add Entity Configurations to Your DbContext
In your application's DbContext, register the provided configurations in OnModelCreating:
using Centeva.Auditing.Configurations;
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new AuditTableConfiguration(auditSchema, auditTable));
modelBuilder.ApplyConfiguration(new AuditDetailConfiguration(auditSchema, auditDetailTable));
// Register other configurations as needed
}
3. Use the Audit Models
using Centeva.Auditing.Models;
// Dual-table audit logging requires both DbSets
public DbSet<AuditTable> Audit { get; set; } // Operation-level audit metadata
public DbSet<AuditDetail> AuditDetail { get; set; } // Field-level change details
4. Generate and Deploy Audit Triggers
using Centeva.Auditing.Helpers;
var config = new AuditConfig(
schema: "dbo",
auditTable: "Audit",
auditDetailTable: "AuditDetail",
connectionString: "your-connection-string"
);
using var creator = new AuditScriptCreator(config);
foreach (var script in creator.GetTriggerScripts(/* optional AuditIgnore rules */))
{
// Execute script against your database
}
Customizing Table and Schema Names
You can configure the schema and table names for the Audit and AuditDetail entities at runtime, allowing you to match your existing database without requiring a migration.
1. Add Settings to appsettings.json
{
"Auditing": {
"AuditSchema": "dbo",
"AuditTable": "Audit",
"AuditDetailTable": "AuditDetail"
}
}
2. Pass Settings to Configuration Classes
Update your DbContext to read these values and pass them to the configuration classes:
using Microsoft.Extensions.Configuration;
using Centeva.Auditing.Configurations;
public class YourDbContext(DbContextOptions<YourDbContext> options, IConfiguration configuration) : DbContext(options)
{
private readonly IConfiguration _configuration = configuration;
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var auditSchema = _configuration["Auditing:AuditSchema"] ?? "dbo";
var auditTable = _configuration["Auditing:AuditTable"] ?? "Audit";
var auditDetailTable = _configuration["Auditing:AuditDetailTable"] ?? "AuditDetail";
modelBuilder.ApplyConfiguration(new AuditTableConfiguration(auditSchema, auditTable));
modelBuilder.ApplyConfiguration(new AuditDetailConfiguration(auditSchema, auditDetailTable));
}
}
3. No Migration Needed
As long as the schema and table names you specify match your existing database, no migration is required.
Configuration Reference
AuditConfig
- Controls schema, table names, and connection string for audit operations.
- Used by
AuditScriptCreatorandAuditMigrationHelper.
AuditTableConfiguration
- Maps the
AuditTableentity to theAudittable. - Configures columns, types, and relationships for operation-level audit data.
AuditDetailConfiguration
- Maps the
AuditDetailentity to theAuditDetailtable. - Configures columns, types, and relationships for field-level change data.
AuditMigrationHelper
- Purpose: Migrates from single-table (v4.x) to dual-table (v5.0+) audit schema.
- Methods:
MigrateSingleToDualTable()- Performs data migration to shadow tablesGenerateMigrationScripts()- Generates SQL swap script for DBA executionRollbackMigration()- Rolls back incomplete migration
AuditScriptCreator
- Purpose: Generates SQL scripts for audit triggers on database tables.
- Important: Always regenerate triggers after schema changes or version upgrades.
AuditIgnore Helpers
- Use
AuditIgnore.Create(schema),AuditIgnore.Create(schema, table), orAuditIgnore.Create(schema, table, column)to specify audit exclusions. - Pass to
AuditScriptCreator.GetTriggerScripts()to exclude specific tables/columns from auditing.
Example: Dependency Injection Setup
If you use dependency injection, register your DbContext and any audit-related services as usual:
services.AddDbContext<YourDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
Architecture
This library exclusively uses a dual-table approach for audit logging:
Audit Table (Operation-Level)
Stores metadata about each audited database operation:
AuditId- Unique identifier for the operationTableName- Name of the table being auditedPK- Primary key value of the affected recordType- Operation type (I=Insert, U=Update, D=Delete)UpdateDate- Timestamp of the operationUserName- User who performed the operation
AuditDetail Table (Field-Level)
Stores individual field changes for each operation:
Id- Unique identifier for the detail recordAuditId- Foreign key to the Audit tableFieldName- Name of the changed fieldOldValue- Previous value (NULL for inserts)NewValue- New value (NULL for deletes)
Benefits Over Single-Table Design
✅ Performance: Normalized schema reduces data duplication and improves query speed
✅ Flexibility: Query operation-level or field-level changes independently
✅ Scalability: Optimized for large databases (tested with 100M+ records)
✅ Maintainability: Cleaner schema with better separation of concerns
✅ Query Efficiency: Indexes can target specific access patterns
Example Query: Get all operations for a specific record:
SELECT * FROM Audit WHERE TableName = 'Users' AND PK = '12345'
Example Query: Get field-level changes for an operation:
SELECT ad.*
FROM AuditDetail ad
INNER JOIN Audit a ON a.AuditId = ad.AuditId
WHERE a.TableName = 'Users' AND a.PK = '12345'
ORDER BY a.UpdateDate DESC
Usage Notes
- Schema Changes: The library exclusively uses dual-table schema. Single-table auditing is not supported in v5.0+.
- Migrations: If you change table names in the configuration, EF Core will generate a migration to rename the table. Table renames are fast metadata operations in SQL Server.
- Column Types: The default configuration uses
nvarchar(max)forOldValueandNewValueinAuditDetailto support large audit values. - Performance: For databases with 100M+ records, use appropriate batch sizes during migration (default: 100,000 records per batch).
- Extensibility: You can extend the models or configurations as needed for your application.
- Upgrading from v4.x: Use
AuditMigrationHelperto migrate existing single-table audit data. See Migration from v4.x.
Compatibility
- .NET 8
- C# 12
- Microsoft.EntityFrameworkCore 8.x
TODO
- Refactor
AuditScriptCreatorto implement an interface and register as a service for improved testability and dependency injection support.
Contributing
Contributions and feedback are welcome. Please open issues or submit pull requests for improvements.
License
Copyright © 2019
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.CSharp (>= 4.7.0)
- Microsoft.Data.SqlClient (>= 6.1.4)
- Microsoft.EntityFrameworkCore (>= 8.0.19)
- Microsoft.EntityFrameworkCore.Relational (>= 8.0.19)
- System.ComponentModel.Annotations (>= 5.0.0)
- System.Data.DataSetExtensions (>= 4.5.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Centeva.Auditing:
| Package | Downloads |
|---|---|
|
Centeva.DatabaseMaintenance
Database update and audit trigger management for .NET applications. |
|
|
Centeva.AuditReverter
Centeva Package used on audit data in SQL Server to revert changes for Integration tests |
GitHub repositories
This package is not used by any popular GitHub repositories.