Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BB-1] Remove audit fields form entity #7

Merged
merged 1 commit into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 3 additions & 100 deletions Core/BuildingBlock.Core.Domain/BaseEntity.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
using System.Collections;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;
using BuildingBlock.Core.Domain.DomainEvents;

namespace BuildingBlock.Core.Domain;
Expand All @@ -11,110 +7,17 @@ public interface IBaseEntity<TKey>
TKey Id { get; set; }
}

public interface IDeleteEntity
public interface IEntity : IBaseEntity<Guid>
{
DateTime? DeletedAt { get; set; }
string? DeletedBy { get; set; }
}

public interface IDeleteEntity<TKey> : IDeleteEntity, IBaseEntity<TKey>
{
}

public interface IAuditEntity
{
DateTime CreatedAt { get; set; }
string CreatedBy { get; set; }
DateTime? UpdatedAt { get; set; }
string? UpdatedBy { get; set; }
}

public interface IAuditEntity<TKey> : IAuditEntity, IDeleteEntity<TKey>
{
}

public abstract class BaseEntity<TKey> : IBaseEntity<TKey>
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual TKey Id { get; set; } = default!;
}

public abstract class DeleteEntity<TKey> : BaseEntity<TKey>, IDeleteEntity<TKey>
{
public DateTime? DeletedAt { get; set; }
public string? DeletedBy { get; set; }
}

public abstract class AuditEntity<TKey> : DeleteEntity<TKey>, IAuditEntity<TKey>
{
public DateTime CreatedAt { get; set; }
public string CreatedBy { get; set; } = null!;
public DateTime? UpdatedAt { get; set; }
public string? UpdatedBy { get; set; }
}

public interface IAggregateRoot : IEntity
{
}

public interface IEntity : IAuditEntity<Guid>
public abstract class Entity : IEntity
{
}

public abstract class Entity : AuditEntity<Guid>, IEntity
{
public void ResetUpdatedTimeStamp()
{
UpdatedAt = null;
UpdatedBy = null;
}

public void Delete(DateTime? deletedAt, string? deletedBy)
{
DeletedAt ??= deletedAt;
DeletedBy ??= deletedBy;

var entityProperties = GetType().GetProperties();

foreach (var entityProperty in entityProperties)
if (IsAGenericList(entityProperty.PropertyType))
DeleteProperty(entityProperty, deletedAt, deletedBy);
}

private void DeleteProperty(PropertyInfo propertyInfo, DateTime? deletedAt, string? deletedBy)
{
var propertyValues = GetPropertyValues(propertyInfo);

var deleteMethod = GetDeleteMethod(propertyInfo);

if (deleteMethod == null) return;

foreach (var value in propertyValues)
{
object?[] parameters = [deletedAt, deletedBy];
deleteMethod.Invoke(value, parameters);
}
}

private static MethodInfo? GetDeleteMethod(PropertyInfo propertyInfo)
{
var elementType = propertyInfo.PropertyType.GetGenericArguments()[0];

return elementType.GetMethod("Delete");
}

private IEnumerable<object?> GetPropertyValues(PropertyInfo propertyInfo)
{
var values = propertyInfo.GetValue(this);

return values is null ? new List<object?>() : (IEnumerable<object?>)values;
}

private static bool IsAGenericList(Type type)
{
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>);
}
public Guid Id { get; set; }
}

public abstract class AggregateRoot : Entity, IAggregateRoot
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using BuildingBlock.Core.Application;
using BuildingBlock.Core.Domain;
using BuildingBlock.Infrastructure.EntityFrameworkCore.Extensions;
using MediatR;
using Microsoft.EntityFrameworkCore;
Expand All @@ -20,22 +19,12 @@ protected BaseDbContext(DbContextOptions options, ICurrentUser currentUser, IMed
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);

foreach (var entityType in builder.Model.GetEntityTypes())
if (typeof(IEntity).IsAssignableFrom(entityType.ClrType))
builder.SetSoftDeleteFilter(entityType.ClrType);
}

public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
await _mediator.DispatchDomainEventsAsync(this);

var auditedEntities = ChangeTracker.Entries()
.Where(e => e is
{ Entity: IEntity, State: EntityState.Added or EntityState.Modified or EntityState.Deleted });

auditedEntities.SetAuditProperties(_currentUser);

return await base.SaveChangesAsync(cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public static class DomainEventExtension
{
public static async Task DispatchDomainEventsAsync(this IMediator mediator, DbContext dbContext)
{
var domainEntities = dbContext.ChangeTracker.Entries<AggregateRoot>().Where(x => x.Entity.DomainEvents.Any())
var domainEntities = dbContext.ChangeTracker.Entries<AggregateRoot>().Where(x => x.Entity.DomainEvents.Count != 0)
.ToList();

var domainEvents = domainEntities.SelectMany(x => x.Entity.DomainEvents).ToList();
Expand Down

This file was deleted.

This file was deleted.

38 changes: 0 additions & 38 deletions Tests/Core/Domain/BaseEntityTest.cs
Original file line number Diff line number Diff line change
@@ -1,45 +1,7 @@
using BuildingBlock.Core.Domain;
using FluentAssertions;

namespace Tests.Core.Domain;

public class EntityTest
{
public class TestEntity : Entity
{
public TestEntity()
{
UpdatedAt = DateTime.Now;
UpdatedBy = "Test";
}

public List<TestEntity> TestEntities { get; set; } = [];
public List<int> TestInts { get; set; } = [1, 2, 3];
public List<string> TestStrings { get; set; } = [];
public TestEntity ChildEntity { get; set; } = null!;
}

public class ResetUpdatedTimeStamp
{
public class ShouldResetUpdatedTimeStamp
{
[Fact]
public void WhenInvoke()
{
// Arrange
var entity = new TestEntity();

// Act
entity.ResetUpdatedTimeStamp();

// Assert
entity.UpdatedAt.Should().BeNull();
entity.UpdatedBy.Should().BeNull();
}
}
}
}

public class AggregateRootTest
{
public class AddDomainEvent
Expand Down
1 change: 0 additions & 1 deletion Tests/Core/Domain/Shared/Utils/EntityHelperTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using BuildingBlock.Core.Domain;
using BuildingBlock.Core.Domain.Exceptions;
using BuildingBlock.Core.Domain.Repositories;
using BuildingBlock.Core.Domain.Shared.Utils;
Expand Down