Skip to main content

Data Operations and Audit Documentation

Overview

EasyAF provides comprehensive data operation management with automatic audit trail creation, user tracking, and data integrity maintenance through a system of interfaces and manager classes. This document explains how these components work together to ensure data consistency and traceability.

Core Interfaces for Data Operations

Identity Management

IIdentifiable<T>

Ensures entities have a unique identifier.
Usage: All entities that need unique identification should implement this interface. The framework automatically generates GUIDs for entities when T is Guid.

Audit Trail Interfaces

ICreatedAuditable

Tracks when an entity was created.

IUpdatedAuditable

Tracks when an entity was last updated.
Note: DateUpdated is nullable since entities may never be updated after creation.

User Tracking Interfaces

ICreatorTrackable<T>

Tracks which user created an entity.

IUpdaterTrackable<T>

Tracks which user last updated an entity.
Note: UpdatedById is nullable since the entity may not have been updated yet.

Automatic Audit Field Population

The EntityManager automatically detects and populates audit fields based on implemented interfaces.

During Insert Operations

During Update Operations

Entity Definition Best Practices

Complete Auditable Entity

Data Operation Flow

Insert Flow

  1. Client creates entity → New instance with business data
  2. Manager.InsertAsync() called → Initiates insert operation
  3. OnInsertingAsync() executed
    • ID generated (if IIdentifiable<Guid>)
    • CreatedById set (if ICreatorTrackable)
    • DateCreated set (if ICreatedAuditable)
  4. Entity added to context → EntityState.Added
  5. SaveChangesAsync() → Database insert
  6. OnInsertedAsync() executed → Post-insert logic (events, notifications)

Update Flow

  1. Entity retrieved and modified → Property changes tracked
  2. Manager.UpdateAsync() called → Initiates update operation
  3. OnUpdatingAsync() executed
    • UpdatedById set (if IUpdaterTrackable)
    • DateUpdated set (if IUpdatedAuditable)
  4. Entity marked modified → EntityState.Modified
  5. SaveChangesAsync() → Database update
  6. OnUpdatedAsync() executed → Post-update logic

Delete Flow

  1. Entity marked for deletion → Soft or hard delete decision
  2. Manager.DeleteAsync() called → Initiates delete operation
  3. OnDeletingAsync() executed → Pre-delete validation/logic
  4. Entity marked deleted → EntityState.Deleted
  5. SaveChangesAsync() → Database delete
  6. OnDeletedAsync() executed → Post-delete cleanup

Advanced Data Operations

Batch Operations

Audit fields are populated for each entity in batch operations:

Direct Operations (Performance)

Direct operations bypass entity loading and audit field population:
Use Cases:
  • Bulk status updates
  • Cleanup operations
  • Performance-critical scenarios
Trade-offs:
  • No automatic audit trail
  • No business logic hooks
  • Better performance

Manual Audit Reset

For special scenarios like entity duplication:

Data Integrity Patterns

Soft Delete Pattern

Versioning Pattern

Active Record Pattern

Security Considerations

User Context

The framework relies on ClaimsPrincipal.Current for user identification:

Audit Trail Immutability

Once set, audit fields should not be modified:

Integration with Change Tracking

DbObservableObject’s change tracking works with audit fields:

Best Practices

  1. Always implement audit interfaces: Provides crucial traceability
  2. Use nullable types for update fields: Not all entities get updated
  3. Leverage automatic population: Don’t manually set audit fields
  4. Consider soft deletes: Maintain data history and recovery options
  5. Use direct operations judiciously: Balance performance vs audit needs
  6. Implement versioning for critical entities: Detect concurrent modifications
  7. Validate user context: Ensure ClaimsPrincipal.Current is available
  8. Test audit trail: Verify fields are populated correctly
  9. Document bypass scenarios: When audit fields won’t be populated
  10. Consider timezone handling: Store as UTC, display in local time