diff --git a/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/DisableAuditingAttribute.cs b/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/DisableAuditingAttribute.cs index 6e31bc2e91..3e2328ba75 100644 --- a/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/DisableAuditingAttribute.cs +++ b/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/DisableAuditingAttribute.cs @@ -5,5 +5,7 @@ namespace Volo.Abp.Auditing; [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property)] public class DisableAuditingAttribute : Attribute { + public bool UpdateModificationProps { get; set; } = true; + public bool PublishEntityEvent { get; set; } = true; } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index e91d08b8c9..0ac45d933b 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -428,20 +428,29 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, case EntityState.Modified: if (entry.Properties.Any(x => x.IsModified && (x.Metadata.ValueGenerated == ValueGenerated.Never || x.Metadata.ValueGenerated == ValueGenerated.OnAdd))) { - if (entry.Properties.Where(x => x.IsModified).All(x => x.Metadata.IsForeignKey())) + var modifiedProperties = entry.Properties.Where(x => x.IsModified).ToList(); + if (modifiedProperties.All(x => x.Metadata.IsForeignKey())) { // Skip `PublishEntityDeletedEvent/PublishEntityUpdatedEvent` if only foreign keys have changed. break; } - ApplyAbpConceptsForModifiedEntity(entry); - if (entry.Entity is ISoftDelete && entry.Entity.As().IsDeleted) + var disableAuditingAttributes = modifiedProperties.Select(x => x.Metadata.PropertyInfo?.GetCustomAttribute()).ToList(); + if (disableAuditingAttributes.Any(x => x == null || x.UpdateModificationProps)) { - EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity); + ApplyAbpConceptsForModifiedEntity(entry); } - else + + if (disableAuditingAttributes.Any(x => x == null || x.PublishEntityEvent)) { - EntityChangeEventHelper.PublishEntityUpdatedEvent(entry.Entity); + if (entry.Entity is ISoftDelete && entry.Entity.As().IsDeleted) + { + EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity); + } + else + { + EntityChangeEventHelper.PublishEntityUpdatedEvent(entry.Entity); + } } } else if (EntityChangeOptions.Value.PublishEntityUpdatedEventWhenNavigationChanges && diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Auditing/Auditing_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Auditing/Auditing_Tests.cs index 8ad0029cc0..a54b1656bf 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Auditing/Auditing_Tests.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Auditing/Auditing_Tests.cs @@ -1,6 +1,10 @@ using System; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using NSubstitute; using Shouldly; +using Volo.Abp.Domain.Entities.Events; using Volo.Abp.TestApp; using Volo.Abp.TestApp.Testing; using Xunit; @@ -9,6 +13,16 @@ namespace Volo.Abp.EntityFrameworkCore.Auditing; public class Auditing_Tests : Auditing_Tests { + protected IEntityChangeEventHelper EntityChangeEventHelper; + + protected override void AfterAddApplication(IServiceCollection services) + { + EntityChangeEventHelper = Substitute.For(); + services.Replace(ServiceDescriptor.Singleton(EntityChangeEventHelper)); + + base.AfterAddApplication(services); + } + [Fact] public async Task Should_Not_Set_Modification_If_Properties_Generated_By_Database() { @@ -24,7 +38,6 @@ public class Auditing_Tests : Auditing_Tests douglas.ShouldNotBeNull(); douglas.LastModificationTime.ShouldBeNull(); - douglas.LastModificationTime.ShouldBeNull(); douglas.LastModifierId.ShouldBeNull(); })); } @@ -71,4 +84,66 @@ public class Auditing_Tests : Auditing_Tests douglas.LastModifierId.ShouldBe(CurrentUserId); })); } + + [Fact] + public async Task Should_Not_Set_Modification_If_Properties_HasDisableAuditing_UpdateModificationProps() + { + await WithUnitOfWorkAsync((async () => + { + var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId); + douglas.DisableAuditingUpdateModificationPropsProperty = Guid.NewGuid().ToString(); + })); + + await WithUnitOfWorkAsync((async () => + { + var douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId); + + douglas.ShouldNotBeNull(); + douglas.LastModificationTime.ShouldBeNull(); + douglas.LastModifierId.ShouldBeNull(); + })); + + EntityChangeEventHelper.Received().PublishEntityUpdatedEvent(Arg.Any()); + } + + [Fact] + public async Task Should_Not_PublishEntityEvent_If_Properties_HasDisableAuditing_PublishEntityEventProperty() + { + await WithUnitOfWorkAsync((async () => + { + var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId); + douglas.DisableAuditingPublishEntityEventProperty = Guid.NewGuid().ToString(); + })); + + await WithUnitOfWorkAsync((async () => + { + var douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId); + + douglas.ShouldNotBeNull(); + douglas.LastModificationTime.ShouldNotBeNull(); + })); + + EntityChangeEventHelper.DidNotReceive().PublishEntityUpdatedEvent(Arg.Any()); + } + + + [Fact] + public async Task Should_Set_Modification_And_PublishEntityEvent_If_Properties_HasDisableAuditing() + { + await WithUnitOfWorkAsync((async () => + { + var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId); + douglas.DisableAuditingProperty = Guid.NewGuid().ToString(); + })); + + await WithUnitOfWorkAsync((async () => + { + var douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId); + + douglas.ShouldNotBeNull(); + douglas.LastModificationTime.ShouldNotBeNull(); + })); + + EntityChangeEventHelper.Received().PublishEntityUpdatedEvent(Arg.Any()); + } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Person.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Person.cs index 5d78236fca..c05d0013d3 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Person.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Person.cs @@ -34,6 +34,15 @@ public class Person : FullAuditedAggregateRoot, IMultiTenant, IHasEntityVe public int EntityVersion { get; set; } + [DisableAuditing(UpdateModificationProps = false)] + public string DisableAuditingUpdateModificationPropsProperty { get; set; } + + [DisableAuditing(PublishEntityEvent = false)] + public string DisableAuditingPublishEntityEventProperty { get; set; } + + [DisableAuditing] + public string DisableAuditingProperty { get; set; } + private Person() { }