Browse Source

Refactor `DisableAuditingAttribute` to allow it to ignore changes to `AuditProperties`.

Resolve #23168
pull/23174/head
maliming 1 year ago
parent
commit
e770f89548
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 2
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/DisableAuditingAttribute.cs
  2. 21
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs
  3. 77
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Auditing/Auditing_Tests.cs
  4. 9
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Person.cs

2
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)] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property)]
public class DisableAuditingAttribute : Attribute public class DisableAuditingAttribute : Attribute
{ {
public bool UpdateModificationProps { get; set; } = true;
public bool PublishEntityEvent { get; set; } = true;
} }

21
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs

@ -428,20 +428,29 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
case EntityState.Modified: case EntityState.Modified:
if (entry.Properties.Any(x => x.IsModified && (x.Metadata.ValueGenerated == ValueGenerated.Never || x.Metadata.ValueGenerated == ValueGenerated.OnAdd))) 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. // Skip `PublishEntityDeletedEvent/PublishEntityUpdatedEvent` if only foreign keys have changed.
break; break;
} }
ApplyAbpConceptsForModifiedEntity(entry); var disableAuditingAttributes = modifiedProperties.Select(x => x.Metadata.PropertyInfo?.GetCustomAttribute<DisableAuditingAttribute>()).ToList();
if (entry.Entity is ISoftDelete && entry.Entity.As<ISoftDelete>().IsDeleted) 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<ISoftDelete>().IsDeleted)
{
EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity);
}
else
{
EntityChangeEventHelper.PublishEntityUpdatedEvent(entry.Entity);
}
} }
} }
else if (EntityChangeOptions.Value.PublishEntityUpdatedEventWhenNavigationChanges && else if (EntityChangeOptions.Value.PublishEntityUpdatedEventWhenNavigationChanges &&

77
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Auditing/Auditing_Tests.cs

@ -1,6 +1,10 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using NSubstitute;
using Shouldly; using Shouldly;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.TestApp; using Volo.Abp.TestApp;
using Volo.Abp.TestApp.Testing; using Volo.Abp.TestApp.Testing;
using Xunit; using Xunit;
@ -9,6 +13,16 @@ namespace Volo.Abp.EntityFrameworkCore.Auditing;
public class Auditing_Tests : Auditing_Tests<AbpEntityFrameworkCoreTestModule> public class Auditing_Tests : Auditing_Tests<AbpEntityFrameworkCoreTestModule>
{ {
protected IEntityChangeEventHelper EntityChangeEventHelper;
protected override void AfterAddApplication(IServiceCollection services)
{
EntityChangeEventHelper = Substitute.For<IEntityChangeEventHelper>();
services.Replace(ServiceDescriptor.Singleton(EntityChangeEventHelper));
base.AfterAddApplication(services);
}
[Fact] [Fact]
public async Task Should_Not_Set_Modification_If_Properties_Generated_By_Database() public async Task Should_Not_Set_Modification_If_Properties_Generated_By_Database()
{ {
@ -24,7 +38,6 @@ public class Auditing_Tests : Auditing_Tests<AbpEntityFrameworkCoreTestModule>
douglas.ShouldNotBeNull(); douglas.ShouldNotBeNull();
douglas.LastModificationTime.ShouldBeNull(); douglas.LastModificationTime.ShouldBeNull();
douglas.LastModificationTime.ShouldBeNull();
douglas.LastModifierId.ShouldBeNull(); douglas.LastModifierId.ShouldBeNull();
})); }));
} }
@ -71,4 +84,66 @@ public class Auditing_Tests : Auditing_Tests<AbpEntityFrameworkCoreTestModule>
douglas.LastModifierId.ShouldBe(CurrentUserId); 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<object>());
}
[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<object>());
}
[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<object>());
}
} }

9
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Person.cs

@ -34,6 +34,15 @@ public class Person : FullAuditedAggregateRoot<Guid>, IMultiTenant, IHasEntityVe
public int EntityVersion { get; set; } 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() private Person()
{ {
} }

Loading…
Cancel
Save