Skip to content

Commit

Permalink
ExtendedBaseAudit
Browse files Browse the repository at this point in the history
  • Loading branch information
vicosanz committed Nov 7, 2023
1 parent ddd52b2 commit e2e16a3
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ namespace Infoware.EntityFrameworkCore.AuditEntity.Extensions
{
public static class DbContextExtensions
{
internal static Task<IBaseAudit?> FactoryBase(Type source)
internal static Task<IBaseAudit?> FactoryBaseAsync(Type source)
{
return Task.FromResult(Activator.CreateInstance(source) as IBaseAudit);
}

public static Task<int> SaveWithAuditsAsync(this DbContext context, ILogJsonSerializer logJsonSerializer,
Func<CancellationToken, Task<int>> baseSaveChangesAsync, CancellationToken cancellationToken = default)
{
return SaveWithAuditsAsync(context, logJsonSerializer, FactoryBase, baseSaveChangesAsync, cancellationToken);
return SaveWithAuditsAsync(context, logJsonSerializer, FactoryBaseAsync, baseSaveChangesAsync, cancellationToken);
}

public static async Task<int> SaveWithAuditsAsync<T>(this DbContext context, ILogJsonSerializer logJsonSerializer,
Func<Type, Task<T?>> factoryAudit, Func<CancellationToken, Task<int>> baseSaveChangesAsync, CancellationToken cancellationToken = default) where T : IBaseAudit
{
var operationsUpdatesDeletes = context.ChangeTracker.Entries()
var operationsUpdatesDeletes = await context.ChangeTracker.Entries()
.Where(e => e.State == EntityState.Modified || e.State == EntityState.Deleted)
.AddEntriesAsync(logJsonSerializer, factoryAudit);

Expand All @@ -31,40 +31,45 @@ public static class DbContextExtensions

var result = await baseSaveChangesAsync(cancellationToken);

var operationsAdds = entriesAdded.AddEntriesAsync(logJsonSerializer, factoryAudit, EntityState.Added);
var operationsAdds = await entriesAdded.AddEntriesAsync(logJsonSerializer, factoryAudit, EntityState.Added);
context.AddRange(operationsUpdatesDeletes);
context.AddRange(operationsAdds);

await baseSaveChangesAsync(cancellationToken);
return result;
}

internal static IBaseAudit? FactoryBase(Type source)
{
return Activator.CreateInstance(source) as IBaseAudit;
}

public static int SaveWithAudits(this DbContext context, ILogJsonSerializer logJsonSerializer, Func<int> baseSaveChanges)
{
return SaveWithAudits(context, logJsonSerializer, FactoryBase, baseSaveChanges);
}

public static int SaveWithAudits<T>(this DbContext context, ILogJsonSerializer logJsonSerializer,
Func<Type, Task<T?>> factoryAudit, Func<int> baseSaveChanges) where T : IBaseAudit
Func<Type, T?> factoryAudit, Func<int> baseSaveChanges) where T : IBaseAudit
{
var operationsUpdatesDeletes = context.ChangeTracker.Entries()
.Where(e => e.State == EntityState.Modified || e.State == EntityState.Deleted)
.AddEntriesAsync(logJsonSerializer, factoryAudit);
.AddEntries(logJsonSerializer, factoryAudit);

var entriesAdded = context.ChangeTracker.Entries()
.Where(e => e.State == EntityState.Added).ToList();

var result = baseSaveChanges();

var operationsAdds = entriesAdded.AddEntriesAsync(logJsonSerializer, factoryAudit, EntityState.Added);
var operationsAdds = entriesAdded.AddEntries(logJsonSerializer, factoryAudit, EntityState.Added);
context.AddRange(operationsUpdatesDeletes);
context.AddRange(operationsAdds);

baseSaveChanges();
return result;
}

internal static async Task<List<IBaseAudit>> AddEntriesAsync<T>(this IEnumerable<EntityEntry> entries, ILogJsonSerializer logJsonSerializer,
internal static async Task<List<IBaseAudit>> AddEntriesAsync<T>(this IEnumerable<EntityEntry> entries, ILogJsonSerializer logJsonSerializer,
Func<Type, Task<T?>> factoryAudit, EntityState? overrideState = null) where T : IBaseAudit
{
var result = new List<IBaseAudit>();
Expand All @@ -88,7 +93,52 @@ public static int SaveWithAudits(this DbContext context, ILogJsonSerializer logJ
if (null != prop && prop.CanWrite)
{
prop.SetValue(objResult, keyValue, null);
}
}

switch (overrideState ?? entry.State)
{
case EntityState.Added:
WriteHistoryAddedState(objResult, entry, logJsonSerializer);
break;
case EntityState.Modified:
WriteHistoryModifiedState(objResult, entry, logJsonSerializer);
break;
case EntityState.Deleted:
WriteHistoryDeletedState(objResult, entry, logJsonSerializer);
break;
}

result.Add(objResult);
}
}
return result;
}

internal static List<IBaseAudit> AddEntries<T>(this IEnumerable<EntityEntry> entries, ILogJsonSerializer logJsonSerializer,
Func<Type, T?> factoryAudit, EntityState? overrideState = null) where T : IBaseAudit
{
var result = new List<IBaseAudit>();
if (entries == null) return result;

foreach (var entry in entries)
{
var auditableEntityType = entry.Entity.GetType().GetInterfaces()
.FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IAuditable<>));
if (auditableEntityType != null)
{
var keyName = entry.Metadata.FindPrimaryKey()!.Properties[0]!;
var keyValue = entry.Property(keyName.Name).CurrentValue;

Type entityAuditType = auditableEntityType.GenericTypeArguments.First();

IBaseAudit? objResult = factoryAudit(entityAuditType);
objResult!.Operation = entry.State.ToString();

PropertyInfo? prop = entityAuditType.GetProperty("TableId", BindingFlags.Public | BindingFlags.Instance);
if (null != prop && prop.CanWrite)
{
prop.SetValue(objResult, keyValue, null);
}

switch (overrideState ?? entry.State)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<Description>Create an individual AuditEntity for selected tables to register changes</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryUrl>https://github.com/vicosanz/Infoware.EntityFrameworkCore.AuditEntity</RepositoryUrl>
<Version>1.0.1</Version>
<Version>1.0.2</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
13 changes: 7 additions & 6 deletions WebApplication1/BlogContext.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Infoware.EntityFrameworkCore.AuditEntity;
using Infoware.EntityFrameworkCore.AuditEntity.Extensions;
using Infoware.SensitiveDataLogger.JsonSerializer;
using Infoware.SRI.DocumentosElectronicos.Context.Models;
using Microsoft.EntityFrameworkCore;
using Test.Models;

Expand Down Expand Up @@ -32,15 +33,15 @@ public override int SaveChanges()
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
return await this.SaveWithAuditsAsync(_logJsonSerializer,
FactoryBase,
(Type source) => {
var result = (IExtendedBaseAudit?) Activator.CreateInstance(source);
result!.UserId = "User1";
result!.UserName = "Username";
return Task.FromResult((IExtendedBaseAudit?)result);
},
(cancellationToken) => base.SaveChangesAsync(cancellationToken),
cancellationToken);
}

internal static Task<IBaseAudit?> FactoryBase(Type source)
{
var result = (IBaseAudit?)Activator.CreateInstance(source);
return Task.FromResult(result);
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions WebApplication1/Migrations/20231107040916_ExtendedBaseAudit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace WebApplication1.Migrations
{
public partial class ExtendedBaseAudit : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "UserId",
table: "BlogAudits",
type: "nvarchar(max)",
nullable: false,
defaultValue: "");

migrationBuilder.AddColumn<string>(
name: "UserName",
table: "BlogAudits",
type: "nvarchar(max)",
nullable: false,
defaultValue: "");
}

protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UserId",
table: "BlogAudits");

migrationBuilder.DropColumn(
name: "UserName",
table: "BlogAudits");
}
}
}
8 changes: 8 additions & 0 deletions WebApplication1/Migrations/BlogContextModelSnapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property<long>("TableId")
.HasColumnType("bigint");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("UserName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("BlogAudits");
Expand Down
3 changes: 2 additions & 1 deletion WebApplication1/Models/BlogAudit.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using Infoware.EntityFrameworkCore.AuditEntity;
using Infoware.SRI.DocumentosElectronicos.Context.Models;

namespace Test.Models
{
public class BlogAudit : BaseAudit<Blog, long>
public class BlogAudit : ExtendedBaseAudit<Blog, long>
{
}
}
26 changes: 26 additions & 0 deletions WebApplication1/Models/ExtendedBaseAudit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Infoware.EntityFrameworkCore.AuditEntity;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Infoware.SRI.DocumentosElectronicos.Context.Models
{
public class ExtendedBaseAudit<TEntity, TUniqueId> : BaseAudit<TEntity, TUniqueId>, IExtendedBaseAudit where TEntity : IAuditable
{
[Required]
public string UserId { get; set; } = null!;

[Required]
public string UserName { get; set; } = null!;
}

public interface IExtendedBaseAudit : IBaseAudit
{
public string UserId { get; set; }

public string UserName { get; set; }
}
}

0 comments on commit e2e16a3

Please sign in to comment.