Skip to content

Commit

Permalink
changed registration
Browse files Browse the repository at this point in the history
  • Loading branch information
HaikAsatryan committed Dec 1, 2024
1 parent 129590f commit 1b87dcb
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 52 deletions.
21 changes: 13 additions & 8 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,21 @@ Install-Package Pandatech.EFCore.AuditBase

1. Inherit from `AuditEntityBase` in your entity classes to enable auditing.
2. Use `MarkAsUpdated(userId)` and `MarkAsDeleted(userId)` methods to handle entity updates and deletions.
3. Apply `DbContextExtensions.UseAuditPropertyValidation` in your DbContext to enforce audit method usage.
3. Apply `OptionsBuilderExtensions.UseAuditBaseValidatorInterceptor` during the DbContext registration in your DI configuration.
4. Leverage `ModelBuilderExtensions.FilterOutDeletedMarkedObjects` to automatically exclude soft-deleted entities from
EF Core queries.

### Registering DbContext with `UseAuditBaseValidatorInterceptor`:

When configuring your `DbContext`, ensure you call `UseAuditBaseValidatorInterceptor` during the service registration phase:
```csharp
var connectionString = configuration.GetConnectionString("Postgres");

builder.Services.AddDbContextPool<PostgresContext>(options =>
options.UseNpgsql(connectionString)
.UseAuditBaseValidatorInterceptor()); // Enforce audit method usage
```

### Entity Inheritance Example:

Assuming you have a `Product` entity in your application, you would inherit from `AuditEntityBase` to include auditing
Expand Down Expand Up @@ -73,8 +84,7 @@ public void DeleteProduct(Product product, long deletingUserId)

### DbContext Configuration:

In your `DbContext`, ensure you call `UseAuditPropertyValidation` to enforce the usage of audit methods and
`FilterOutDeletedMarkedObjects` to apply the global filter for soft-deleted entities:
In your `DbContext`, you can use the `FilterOutDeletedMarkedObjects` method to apply a global query filter for soft-deleted entities:

```csharp
using Microsoft.EntityFrameworkCore;
Expand All @@ -90,11 +100,6 @@ public class MyDbContext : DbContext

modelBuilder.FilterOutDeletedMarkedObjects(); // Apply global query filter for soft deletes
}

public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
{
this.UseAuditPropertyValidation(); // Enforce audit method usage
}
}
```

Expand Down
42 changes: 0 additions & 42 deletions src/EFCore.AuditBase/DbContextExtension.cs

This file was deleted.

4 changes: 2 additions & 2 deletions src/EFCore.AuditBase/EFCore.AuditBase.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
<PackageReadmeFile>Readme.md</PackageReadmeFile>
<Authors>Pandatech</Authors>
<Copyright>MIT</Copyright>
<Version>2.0.0</Version>
<Version>3.0.0</Version>
<PackageId>Pandatech.EFCore.AuditBase</PackageId>
<Title>Pandatech EFCore AuditBase</Title>
<PackageTags>Pandatech, library, audit, optimistic lock, tracking, efcore, soft delete, versioning</PackageTags>
<Description>Pandatech.EFCore.AuditBase provides a robust auditing solution for EF Core applications, ensuring traceability and integrity of entity modifications. It seamlessly integrates auditing capabilities into your EF Core entities, enforcing best practices for entity state changes, deletion handling, and versioning to support concurrency control. Ideal for applications requiring a reliable audit trail and compliance with data handling standards.</Description>
<RepositoryUrl>https://github.com/PandaTechAM/be-lib-efcore-audit-base</RepositoryUrl>
<PackageReleaseNotes>.Net 9 Upgrade</PackageReleaseNotes>
<PackageReleaseNotes>Changed registration way. Implementation is the same. Check Readme.md</PackageReleaseNotes>
</PropertyGroup>

<ItemGroup>
Expand Down
14 changes: 14 additions & 0 deletions src/EFCore.AuditBase/Extensions/DbOptionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Microsoft.EntityFrameworkCore;
using EFCore.AuditBase.Interceptors;

namespace EFCore.AuditBase.Extensions;

public static class OptionsBuilderExtensions
{
public static DbContextOptionsBuilder UseAuditBaseValidatorInterceptor(this DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.AddInterceptors(new AuditPropertyValidationInterceptor());

return optionsBuilder;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;

namespace EFCore.AuditBase.Interceptors;

internal class AuditPropertyValidationInterceptor : SaveChangesInterceptor
{
public override InterceptionResult<int> SavingChanges(DbContextEventData eventData,
InterceptionResult<int> result)
{
if (eventData.Context is not null)
{
ValidateAuditMethodUsage(eventData.Context);
}

return base.SavingChanges(eventData, result);
}

public override ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData eventData,
InterceptionResult<int> result,
CancellationToken cancellationToken = default)
{
if (eventData.Context is not null)
{
ValidateAuditMethodUsage(eventData.Context);
}

return base.SavingChangesAsync(eventData, result, cancellationToken);
}

private static void ValidateAuditMethodUsage(DbContext context)
{
var entries = context.ChangeTracker
.Entries<AuditEntityBase>()
.Where(e => e.State == EntityState.Modified);

foreach (var entry in entries)
{
var entityName = entry.Entity.GetType()
.Name;

if (entry.State is not EntityState.Modified)
{
continue;
}

var originalVersion = entry.OriginalValues[nameof(AuditEntityBase.Version)] as int?;
var currentVersion = entry.CurrentValues[nameof(AuditEntityBase.Version)] as int?;

if (originalVersion == currentVersion)
{
throw new InvalidOperationException(
$"Entity '{entityName}' must be updated using MarkAsUpdated method. Missing or incorrect audit fields for update.");
}
}
}
}

0 comments on commit 1b87dcb

Please sign in to comment.