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 7a903aa550..f8dcffee52 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -503,7 +503,23 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, protected virtual IEnumerable GetAllPropertyEntries(EntityEntry entry) { - return entry.Properties.Concat(entry.ComplexProperties.SelectMany(x => x.Properties)); + return entry.Properties.Concat(GetAllComplexPropertyEntries(entry.ComplexProperties)); + } + + protected virtual IEnumerable GetAllComplexPropertyEntries(IEnumerable complexPropertyEntries) + { + foreach (var complexPropertyEntry in complexPropertyEntries) + { + foreach (var propertyEntry in complexPropertyEntry.Properties) + { + yield return propertyEntry; + } + + foreach (var nestedPropertyEntry in GetAllComplexPropertyEntries(complexPropertyEntry.ComplexProperties)) + { + yield return nestedPropertyEntry; + } + } } protected virtual bool IsOnlyForeignKeysModified(EntityEntry entry) 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 e13b9999d6..3fe863c046 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 @@ -89,13 +89,13 @@ public class Auditing_Tests : Auditing_Tests [Fact] public async Task Should_Set_Modification_If_Complex_Properties_Changed() { - var street = Guid.NewGuid().ToString(); + var city = Guid.NewGuid().ToString(); await WithUnitOfWorkAsync((async () => { var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId); douglas.ContactInformation ??= new PersonContactInformation(); - douglas.ContactInformation.Street = street; + douglas.ContactInformation.Location.City = city; })); await WithUnitOfWorkAsync((async () => @@ -104,7 +104,7 @@ public class Auditing_Tests : Auditing_Tests douglas.ShouldNotBeNull(); douglas.ContactInformation.ShouldNotBeNull(); - douglas.ContactInformation!.Street.ShouldBe(street); + douglas.ContactInformation!.Location.City.ShouldBe(city); douglas.LastModificationTime.ShouldNotBeNull(); douglas.LastModificationTime.Value.ShouldBeLessThanOrEqualTo(Clock.Now); douglas.LastModifierId.ShouldBe(CurrentUserId); @@ -156,6 +156,28 @@ public class Auditing_Tests : Auditing_Tests EntityChangeEventHelper.Received().PublishEntityUpdatedEvent(Arg.Any()); } + [Fact] + public async Task Should_Not_Set_Modification_If_Nested_ComplexProperties_HasDisableAuditing_UpdateModificationProps() + { + await WithUnitOfWorkAsync((async () => + { + var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId); + douglas.ContactInformation ??= new PersonContactInformation(); + douglas.ContactInformation.Location.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() { @@ -197,6 +219,27 @@ public class Auditing_Tests : Auditing_Tests EntityChangeEventHelper.DidNotReceive().PublishEntityUpdatedEvent(Arg.Any()); } + [Fact] + public async Task Should_Not_PublishEntityEvent_If_Nested_ComplexProperties_HasDisableAuditing_PublishEntityEventProperty() + { + await WithUnitOfWorkAsync((async () => + { + var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId); + douglas.ContactInformation ??= new PersonContactInformation(); + douglas.ContactInformation.Location.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() @@ -238,4 +281,25 @@ public class Auditing_Tests : Auditing_Tests EntityChangeEventHelper.Received().PublishEntityUpdatedEvent(Arg.Any()); } + + [Fact] + public async Task Should_Set_Modification_And_PublishEntityEvent_If_Nested_ComplexProperties_HasDisableAuditing() + { + await WithUnitOfWorkAsync((async () => + { + var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId); + douglas.ContactInformation ??= new PersonContactInformation(); + douglas.ContactInformation.Location.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.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs index 096740eb41..96f4b1a2e1 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs @@ -81,6 +81,10 @@ public class TestMigrationsDbContext : AbpDbContext b.ComplexProperty(x => x.ContactInformation, cb => { cb.Property(x => x.Street).IsRequired(); + cb.ComplexProperty(x => x.Location, locationBuilder => + { + locationBuilder.Property(x => x.City).IsRequired(); + }); }); }); diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs index 62120f4d8b..2b95877bed 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs @@ -95,6 +95,10 @@ public class TestAppDbContext : AbpDbContext, IThirdDbContext, b.ComplexProperty(x => x.ContactInformation, cb => { cb.Property(x => x.Street).IsRequired(); + cb.ComplexProperty(x => x.Location, locationBuilder => + { + locationBuilder.Property(x => x.City).IsRequired(); + }); }); }); 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 834ae49320..9da2357d70 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 @@ -91,6 +91,22 @@ public class PersonContactInformation { public string Street { get; set; } = string.Empty; + public PersonContactLocation Location { get; set; } = new(); + + [DisableAuditing(UpdateModificationProps = false)] + public string? DisableAuditingUpdateModificationPropsProperty { get; set; } + + [DisableAuditing(PublishEntityEvent = false)] + public string? DisableAuditingPublishEntityEventProperty { get; set; } + + [DisableAuditing] + public string? DisableAuditingProperty { get; set; } +} + +public class PersonContactLocation +{ + public string City { get; set; } = string.Empty; + [DisableAuditing(UpdateModificationProps = false)] public string? DisableAuditingUpdateModificationPropsProperty { get; set; }