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 bdc456b776..4ef6057943 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 @@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Volo.Abp.Auditing; +using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities; using Volo.Abp.Json; @@ -246,6 +247,26 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory return false; } + if (propertyEntry.OriginalValue is ExtraPropertyDictionary originalValue && propertyEntry.CurrentValue is ExtraPropertyDictionary currentValue) + { + if (originalValue.IsNullOrEmpty() && currentValue.IsNullOrEmpty()) + { + return false; + } + + if (!originalValue.Select(x => x.Key).SequenceEqual(currentValue.Select(x => x.Key))) + { + return true; + } + + if (!originalValue.Select(x => x.Value).SequenceEqual(currentValue.Select(x => x.Value))) + { + return true; + } + + return defaultValue; + } + var isModified = !(propertyEntry.OriginalValue?.Equals(propertyEntry.CurrentValue) ?? propertyEntry.CurrentValue == null); if (isModified) { 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 53a5a7ec2e..e72f67bbc3 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 @@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using NSubstitute; using Volo.Abp.Auditing.App.Entities; +using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; using Volo.Abp.Uow; @@ -44,7 +45,7 @@ namespace Volo.Abp.Auditing await _auditingStore.Received().SaveAsync(Arg.Any()); } - + [Fact] public async Task Should_Write_AuditLog_For_Classes_That_Implement_IAuditingEnabled_Without_An_Explicit_Scope() { @@ -280,6 +281,37 @@ namespace Volo.Abp.Auditing .Where(y => y.PropertyName != nameof(AppEntityWithAuditedAndHasCustomAuditingProperties .ExtraProperties)) .All(y => GetBaseAuditPropertyNames().Contains(y.PropertyName)))); +#pragma warning restore 4014 + } + + [Fact] + public virtual async Task Should_Write_AuditLog_Without_ExtraPropertyDictionary() + { + var entityId = Guid.NewGuid(); + var repository = ServiceProvider.GetRequiredService>(); + var appEntityWithAudited = new AppEntityWithAudited(entityId, "test name"); + appEntityWithAudited.SetProperty("No", 123456); + await repository.InsertAsync(appEntityWithAudited); + + using (var scope = _auditingManager.BeginScope()) + { + using (var uow = _unitOfWorkManager.Begin()) + { + var entity = await repository.GetAsync(entityId); + entity.Name = "new test name"; + + await repository.UpdateAsync(entity); + + await uow.CompleteAsync(); + } + + await scope.SaveAsync(); + } + +#pragma warning disable 4014 + _auditingStore.Received().SaveAsync(Arg.Is(x => x.EntityChanges.Count == 1 + && x.EntityChanges[0].PropertyChanges.Count == 1 + && x.EntityChanges[0].PropertyChanges[0].PropertyName == nameof(AppEntityWithAudited.Name))); #pragma warning restore 4014 } }