diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs index 8db091eb30..796c6e20fb 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; @@ -241,6 +242,11 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory } } + if (IsBaseAuditProperty(propertyInfo, entityType)) + { + return false; + } + var isModified = !(propertyEntry.OriginalValue?.Equals(propertyEntry.CurrentValue) ?? propertyEntry.CurrentValue == null); if (isModified) { @@ -250,6 +256,59 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory return defaultValue; } + private bool IsBaseAuditProperty(PropertyInfo propertyInfo, Type entityType) + { + if (entityType.IsAssignableTo() + && propertyInfo.Name == nameof(IHasCreationTime.CreationTime)) + { + return true; + } + + if (entityType.IsAssignableTo() + && propertyInfo.Name == nameof(IMayHaveCreator.CreatorId)) + { + return true; + } + + if (entityType.IsAssignableTo() + && propertyInfo.Name == nameof(IMustHaveCreator.CreatorId)) + { + return true; + } + + if (entityType.IsAssignableTo() + && propertyInfo.Name == nameof(IHasModificationTime.LastModificationTime)) + { + return true; + } + + if (entityType.IsAssignableTo() + && propertyInfo.Name == nameof(IModificationAuditedObject.LastModifierId)) + { + return true; + } + + if (entityType.IsAssignableTo() + && propertyInfo.Name == nameof(ISoftDelete.IsDeleted)) + { + return true; + } + + if (entityType.IsAssignableTo() + && propertyInfo.Name == nameof(IHasDeletionTime.DeletionTime)) + { + return true; + } + + if (entityType.IsAssignableTo() + && propertyInfo.Name == nameof(IDeletionAuditedObject.DeleterId)) + { + return true; + } + + return false; + } + /// /// Updates change time, entity id and foreign keys after SaveChanges is called. /// @@ -313,4 +372,4 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory } } } -} +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/Entities/AppEntityWithAuditedAndHasCustomAuditingProperties.cs b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/Entities/AppEntityWithAuditedAndHasCustomAuditingProperties.cs new file mode 100644 index 0000000000..9ff57b286d --- /dev/null +++ b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/Entities/AppEntityWithAuditedAndHasCustomAuditingProperties.cs @@ -0,0 +1,26 @@ +using System; +using Volo.Abp.Domain.Entities; + +namespace Volo.Abp.Auditing.App.Entities +{ + [Audited] + public class AppEntityWithAuditedAndHasCustomAuditingProperties : AggregateRoot + { + protected AppEntityWithAuditedAndHasCustomAuditingProperties() + { + } + + public AppEntityWithAuditedAndHasCustomAuditingProperties(Guid id) + : base(id) + { + } + + public DateTime? CreationTime { get; set; } + public Guid? CreatorId { get; set; } + public DateTime? LastModificationTime { get; set; } + public Guid? LastModifierId { get; set; } + public bool IsDeleted { get; set; } + public DateTime? DeletionTime { get; set; } + public Guid? DeleterId { get; set; } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/Entities/AppFullAuditedEntityWithAudited.cs b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/Entities/AppFullAuditedEntityWithAudited.cs new file mode 100644 index 0000000000..def7e0d44c --- /dev/null +++ b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/Entities/AppFullAuditedEntityWithAudited.cs @@ -0,0 +1,21 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; + +namespace Volo.Abp.Auditing.App.Entities +{ + [Audited] + public class AppFullAuditedEntityWithAudited : FullAuditedAggregateRoot + { + protected AppFullAuditedEntityWithAudited() + { + } + + public AppFullAuditedEntityWithAudited(Guid id, string name) + : base(id) + { + Name = name; + } + + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/EntityFrameworkCore/AbpAuditingTestDbContext.cs b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/EntityFrameworkCore/AbpAuditingTestDbContext.cs index 0968bf2cc2..d6b2d2b167 100644 --- a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/EntityFrameworkCore/AbpAuditingTestDbContext.cs +++ b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/EntityFrameworkCore/AbpAuditingTestDbContext.cs @@ -17,6 +17,10 @@ namespace Volo.Abp.Auditing.App.EntityFrameworkCore public DbSet AppEntityWithPropertyHasAudited { get; set; } public DbSet AppEntityWithSelector { get; set; } + + public DbSet AppFullAuditedEntityWithAudited { get; set; } + + public DbSet AppEntityWithAuditedAndHasCustomAuditingProperties { get; set; } public AbpAuditingTestDbContext(DbContextOptions options) : base(options) diff --git a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs index 2887eb8510..8c647c92c4 100644 --- a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs +++ b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; @@ -215,5 +216,63 @@ namespace Volo.Abp.Auditing #pragma warning restore 4014 } + private static List GetBaseAuditPropertyNames() + { + return new List + { + nameof(IHasCreationTime.CreationTime), + nameof(IMustHaveCreator.CreatorId), + nameof(IHasModificationTime.LastModificationTime), + nameof(IModificationAuditedObject.LastModifierId), + nameof(ISoftDelete.IsDeleted), + nameof(IHasDeletionTime.DeletionTime), + nameof(IDeletionAuditedObject.DeleterId) + }; + } + + [Fact] + public virtual async Task Should_Write_AuditLog_Ignoring_Base_Auditing_Properties_For_Entity_That_Has_Audited_Attribute() + { + using (var scope = _auditingManager.BeginScope()) + { + var repository = ServiceProvider.GetRequiredService>(); + await repository.InsertAsync(new AppFullAuditedEntityWithAudited(Guid.NewGuid(), "test name")); + await scope.SaveAsync(); + } + +#pragma warning disable 4014 + _auditingStore.Received().SaveAsync(Arg.Is(x => x.EntityChanges.Count == 1 + && x.EntityChanges[0].PropertyChanges.Any(y => + !GetBaseAuditPropertyNames().Contains(y.PropertyName)))); +#pragma warning restore 4014 + } + + [Fact] + public virtual async Task Should_Write_AuditLog_Including_Custom_Base_Auditing_Properties_For_Entity_That_Has_Audited_Attribute() + { + using (var scope = _auditingManager.BeginScope()) + { + var repository = ServiceProvider.GetRequiredService>(); + await repository.InsertAsync(new AppEntityWithAuditedAndHasCustomAuditingProperties(Guid.NewGuid()) + { + CreationTime = DateTime.Now, + CreatorId = Guid.NewGuid(), + LastModificationTime = DateTime.Now, + LastModifierId = Guid.NewGuid(), + IsDeleted = true, + DeletionTime = DateTime.Now, + DeleterId = Guid.NewGuid() + }); + await scope.SaveAsync(); + } + +#pragma warning disable 4014 + _auditingStore.Received().SaveAsync(Arg.Is(x => x.EntityChanges.Count == 1 + && x.EntityChanges[0].PropertyChanges + .Where(y => y.PropertyName != nameof(AppEntityWithAuditedAndHasCustomAuditingProperties + .ExtraProperties)) + .All(y => GetBaseAuditPropertyNames().Contains(y.PropertyName)))); +#pragma warning restore 4014 + } } }