Browse Source

Publish `EntityUpdatedEvent` when navigation changes.

pull/19079/head
maliming 3 years ago
committed by maliming
parent
commit
bae8008beb
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 10
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/AbpEntityChangeOptions.cs
  2. 48
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs
  3. 2
      framework/src/Volo.Abp.TestBase/Volo/Abp/Testing/Utils/ITestCounter.cs
  4. 8
      framework/src/Volo.Abp.TestBase/Volo/Abp/Testing/Utils/TestCounter.cs
  5. 1
      framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs
  6. 7
      framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkEventRecord.cs
  7. 5
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs
  8. 4
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DomainEvents/DomainEvents_Tests.cs
  9. 11
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs
  10. 11
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs
  11. 3
      framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/TestApp/MemoryDb/TestAppMemoryDbContext.cs
  12. 7
      framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Serializer/MongoDB_DateTimeKind_Tests.cs
  13. 2
      framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/ITestAppMongoDbContext.cs
  14. 4
      framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs
  15. 67
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/AppEntityWithNavigations.cs
  16. 227
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs
  17. 3
      modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_User_Change_Event_Tests.cs

10
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/AbpEntityChangeOptions.cs

@ -0,0 +1,10 @@
namespace Volo.Abp.Domain.Entities.Events;
public class AbpEntityChangeOptions
{
/// <summary>
/// Default: true.
/// Publish the EntityUpdatedEvent when any navigation property changes.
/// </summary>
public bool PublishEntityUpdatedEventWhenNavigationChanges { get; set; } = true;
}

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

@ -53,6 +53,8 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
public IEntityChangeEventHelper EntityChangeEventHelper => LazyServiceProvider.LazyGetService<IEntityChangeEventHelper>(NullEntityChangeEventHelper.Instance); public IEntityChangeEventHelper EntityChangeEventHelper => LazyServiceProvider.LazyGetService<IEntityChangeEventHelper>(NullEntityChangeEventHelper.Instance);
public IOptions<AbpEntityChangeOptions> EntityChangeOptions => LazyServiceProvider.LazyGetRequiredService<IOptions<AbpEntityChangeOptions>>();
public IAuditPropertySetter AuditPropertySetter => LazyServiceProvider.LazyGetRequiredService<IAuditPropertySetter>(); public IAuditPropertySetter AuditPropertySetter => LazyServiceProvider.LazyGetRequiredService<IAuditPropertySetter>();
public IEntityHistoryHelper EntityHistoryHelper => LazyServiceProvider.LazyGetService<IEntityHistoryHelper>(NullEntityHistoryHelper.Instance); public IEntityHistoryHelper EntityHistoryHelper => LazyServiceProvider.LazyGetService<IEntityHistoryHelper>(NullEntityHistoryHelper.Instance);
@ -306,14 +308,15 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
} }
} }
private void PublishEventsForTrackedEntity(EntityEntry entry) protected virtual void PublishEventsForTrackedEntity(EntityEntry entry)
{ {
switch (entry.State) switch (entry.State)
{ {
case EntityState.Added: case EntityState.Added:
ApplyAbpConceptsForAddedEntity(entry); ApplyAbpConceptsForAddedEntity(entry);
EntityChangeEventHelper.PublishEntityCreatedEvent(entry.Entity); EntityChangeEventHelper.PublishEntityCreatedEvent(entry.Entity);
break; break;
case EntityState.Modified: case EntityState.Modified:
ApplyAbpConceptsForModifiedEntity(entry); ApplyAbpConceptsForModifiedEntity(entry);
if (entry.Properties.Any(x => x.IsModified && x.Metadata.ValueGenerated == ValueGenerated.Never)) if (entry.Properties.Any(x => x.IsModified && x.Metadata.ValueGenerated == ValueGenerated.Never))
@ -327,13 +330,52 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
EntityChangeEventHelper.PublishEntityUpdatedEvent(entry.Entity); EntityChangeEventHelper.PublishEntityUpdatedEvent(entry.Entity);
} }
} }
break; break;
case EntityState.Deleted: case EntityState.Deleted:
ApplyAbpConceptsForDeletedEntity(entry); ApplyAbpConceptsForDeletedEntity(entry);
EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity); EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity);
break; break;
} }
foreach (var entityEntry in new[] { entry }.Where(HasEntityEntryChanged).Concat(ChangeTracker.Entries().Where(HasEntityEntryChanged)).DistinctBy(x => x.Entity))
{
ApplyAbpConceptsForModifiedEntity(entry);
if (entityEntry.Entity is ISoftDelete && entityEntry.Entity.As<ISoftDelete>().IsDeleted)
{
EntityChangeEventHelper.PublishEntityDeletedEvent(entityEntry.Entity);
}
else
{
EntityChangeEventHelper.PublishEntityUpdatedEvent(entityEntry.Entity);
}
}
}
protected virtual bool HasEntityEntryChanged(EntityEntry entry)
{
if (entry.State != EntityState.Modified && entry.State != EntityState.Unchanged)
{
return false;
}
var changed = entry.State == EntityState.Modified && entry.Properties.Any(x => x.IsModified && (x.Metadata.ValueGenerated == ValueGenerated.Never || x.Metadata.ValueGenerated == ValueGenerated.OnAdd));
if (changed)
{
return true;
}
if (!changed &&
EntityChangeOptions.Value.PublishEntityUpdatedEventWhenNavigationChanges)
{
if (entry.Navigations.Any(navigation => navigation.IsModified || (navigation is ReferenceEntry && navigation.As<ReferenceEntry>().TargetEntry?.State == EntityState.Modified)))
{
changed = true;
}
}
return changed;
} }
protected virtual void HandlePropertiesBeforeSave() protected virtual void HandlePropertiesBeforeSave()

2
framework/src/Volo.Abp.TestBase/Volo/Abp/Testing/Utils/ITestCounter.cs

@ -9,4 +9,6 @@ public interface ITestCounter
int Increment(string name); int Increment(string name);
int GetValue(string name); int GetValue(string name);
void ResetCount(string name);
} }

8
framework/src/Volo.Abp.TestBase/Volo/Abp/Testing/Utils/TestCounter.cs

@ -39,4 +39,12 @@ public class TestCounter : ITestCounter, ISingletonDependency
return _values.GetOrDefault(name); return _values.GetOrDefault(name);
} }
} }
public void ResetCount(string name)
{
lock (_values)
{
_values[name] = 0;
}
}
} }

1
framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs

@ -272,6 +272,7 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency
} }
else else
{ {
eventRecord.SetOrder(eventRecords[foundIndex].EventOrder);
eventRecords[foundIndex] = eventRecord; eventRecords[foundIndex] = eventRecord;
} }
} }

7
framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkEventRecord.cs

@ -9,7 +9,7 @@ public class UnitOfWorkEventRecord
public Type EventType { get; } public Type EventType { get; }
public long EventOrder { get; } public long EventOrder { get; protected set; }
public bool UseOutbox { get; } public bool UseOutbox { get; }
@ -29,4 +29,9 @@ public class UnitOfWorkEventRecord
EventOrder = eventOrder; EventOrder = eventOrder;
UseOutbox = useOutbox; UseOutbox = useOutbox;
} }
public void SetOrder(long order)
{
EventOrder = order;
}
} }

5
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs

@ -48,6 +48,11 @@ public class AbpEntityFrameworkCoreTestModule : AbpModule
{ {
opt.DefaultWithDetailsFunc = q => q.Include(p => p.Books); opt.DefaultWithDetailsFunc = q => q.Include(p => p.Books);
}); });
options.Entity<AppEntityWithNavigations>(opt =>
{
opt.DefaultWithDetailsFunc = q => q.Include(p => p.OneToOne).Include(p => p.OneToMany).Include(p => p.ManyToMany);
});
}); });
context.Services.AddAbpDbContext<HostTestAppDbContext>(options => context.Services.AddAbpDbContext<HostTestAppDbContext>(options =>

4
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DomainEvents/DomainEvents_Tests.cs

@ -5,3 +5,7 @@ namespace Volo.Abp.EntityFrameworkCore.DomainEvents;
public class DomainEvents_Tests : DomainEvents_Tests<AbpEntityFrameworkCoreTestModule> public class DomainEvents_Tests : DomainEvents_Tests<AbpEntityFrameworkCoreTestModule>
{ {
} }
public class AbpEntityChangeOptions_DomainEvents_Tests : AbpEntityChangeOptions_DomainEvents_Tests<AbpEntityFrameworkCoreTestModule>
{
}

11
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs

@ -26,6 +26,8 @@ public class TestMigrationsDbContext : AbpDbContext<TestMigrationsDbContext>
public DbSet<Category> Categories { get; set; } public DbSet<Category> Categories { get; set; }
public DbSet<AppEntityWithNavigations> AppEntityWithNavigations { get; set; }
public TestMigrationsDbContext(DbContextOptions<TestMigrationsDbContext> options) public TestMigrationsDbContext(DbContextOptions<TestMigrationsDbContext> options)
: base(options) : base(options)
{ {
@ -64,5 +66,14 @@ public class TestMigrationsDbContext : AbpDbContext<TestMigrationsDbContext>
{ {
b.HasAbpQueryFilter(e => e.Name.StartsWith("abp")); b.HasAbpQueryFilter(e => e.Name.StartsWith("abp"));
}); });
modelBuilder.Entity<AppEntityWithNavigations>(b =>
{
b.ConfigureByConvention();
b.OwnsOne(v => v.AppEntityWithValueObjectAddress);
b.HasOne(x => x.OneToOne).WithOne().HasForeignKey<AppEntityWithNavigationChildOneToOne>(x => x.Id);
b.HasMany(x => x.OneToMany).WithOne().HasForeignKey(x => x.AppEntityWithNavigationId);
b.HasMany(x => x.ManyToMany).WithMany();
});
} }
} }

11
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs

@ -34,6 +34,8 @@ public class TestAppDbContext : AbpDbContext<TestAppDbContext>, IThirdDbContext,
public DbSet<Category> Categories { get; set; } public DbSet<Category> Categories { get; set; }
public DbSet<AppEntityWithNavigations> AppEntityWithNavigations { get; set; }
public TestAppDbContext(DbContextOptions<TestAppDbContext> options) public TestAppDbContext(DbContextOptions<TestAppDbContext> options)
: base(options) : base(options)
{ {
@ -92,6 +94,15 @@ public class TestAppDbContext : AbpDbContext<TestAppDbContext>, IThirdDbContext,
b.HasAbpQueryFilter(e => e.Name.StartsWith("abp")); b.HasAbpQueryFilter(e => e.Name.StartsWith("abp"));
}); });
modelBuilder.Entity<AppEntityWithNavigations>(b =>
{
b.ConfigureByConvention();
b.OwnsOne(v => v.AppEntityWithValueObjectAddress);
b.HasOne(x => x.OneToOne).WithOne().HasForeignKey<AppEntityWithNavigationChildOneToOne>(x => x.Id);
b.HasMany(x => x.OneToMany).WithOne().HasForeignKey(x => x.AppEntityWithNavigationId);
b.HasMany(x => x.ManyToMany).WithMany();
});
modelBuilder.TryConfigureObjectExtensions<TestAppDbContext>(); modelBuilder.TryConfigureObjectExtensions<TestAppDbContext>();
} }
} }

3
framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/TestApp/MemoryDb/TestAppMemoryDbContext.cs

@ -11,7 +11,8 @@ public class TestAppMemoryDbContext : MemoryDbContext
private static readonly Type[] EntityTypeList = { private static readonly Type[] EntityTypeList = {
typeof(Person), typeof(Person),
typeof(EntityWithIntPk), typeof(EntityWithIntPk),
typeof(Product) typeof(Product),
typeof(AppEntityWithNavigations)
}; };
public override IReadOnlyList<Type> GetEntityTypes() public override IReadOnlyList<Type> GetEntityTypes()

7
framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Serializer/MongoDB_DateTimeKind_Tests.cs

@ -21,9 +21,6 @@ public abstract class MongoDB_DateTimeKind_Tests : DateTimeKind_Tests<AbpMongoDb
// We must reconfigure it in the new unit test. // We must reconfigure it in the new unit test.
foreach (var registeredClassMap in BsonClassMap.GetRegisteredClassMaps()) foreach (var registeredClassMap in BsonClassMap.GetRegisteredClassMaps())
{ {
var frozen = registeredClassMap.GetType().BaseType?.GetField("_frozen", BindingFlags.NonPublic | BindingFlags.Instance);
frozen?.SetValue(registeredClassMap, false);
foreach (var declaredMemberMap in registeredClassMap.DeclaredMemberMaps) foreach (var declaredMemberMap in registeredClassMap.DeclaredMemberMaps)
{ {
var serializer = declaredMemberMap.GetSerializer(); var serializer = declaredMemberMap.GetSerializer();
@ -46,8 +43,6 @@ public abstract class MongoDB_DateTimeKind_Tests : DateTimeKind_Tests<AbpMongoDb
} }
} }
} }
frozen?.SetValue(registeredClassMap, true);
} }
} }
} }
@ -62,6 +57,7 @@ public class DateTimeKindTests_Unspecified : MongoDB_DateTimeKind_Tests
} }
} }
[Collection(MongoTestCollection.Name)]
public class DateTimeKindTests_Local : MongoDB_DateTimeKind_Tests public class DateTimeKindTests_Local : MongoDB_DateTimeKind_Tests
{ {
protected override void AfterAddApplication(IServiceCollection services) protected override void AfterAddApplication(IServiceCollection services)
@ -72,6 +68,7 @@ public class DateTimeKindTests_Local : MongoDB_DateTimeKind_Tests
} }
} }
[Collection(MongoTestCollection.Name)]
public class DateTimeKindTests_Utc : MongoDB_DateTimeKind_Tests public class DateTimeKindTests_Utc : MongoDB_DateTimeKind_Tests
{ {
protected override void AfterAddApplication(IServiceCollection services) protected override void AfterAddApplication(IServiceCollection services)

2
framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/ITestAppMongoDbContext.cs

@ -14,4 +14,6 @@ public interface ITestAppMongoDbContext : IAbpMongoDbContext
IMongoCollection<City> Cities { get; } IMongoCollection<City> Cities { get; }
IMongoCollection<Product> Products { get; } IMongoCollection<Product> Products { get; }
IMongoCollection<AppEntityWithNavigations> AppEntityWithNavigations { get; }
} }

4
framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs

@ -24,9 +24,11 @@ public class TestAppMongoDbContext : AbpMongoDbContext, ITestAppMongoDbContext,
public IMongoCollection<ThirdDbContextDummyEntity> DummyEntities => Collection<ThirdDbContextDummyEntity>(); public IMongoCollection<ThirdDbContextDummyEntity> DummyEntities => Collection<ThirdDbContextDummyEntity>();
public IMongoCollection<FourthDbContextDummyEntity> FourthDummyEntities => Collection<FourthDbContextDummyEntity>(); public IMongoCollection<FourthDbContextDummyEntity> FourthDummyEntities => Collection<FourthDbContextDummyEntity>();
public IMongoCollection<Product> Products => Collection<Product>(); public IMongoCollection<Product> Products => Collection<Product>();
public IMongoCollection<AppEntityWithNavigations> AppEntityWithNavigations => Collection<AppEntityWithNavigations>();
protected internal override void CreateModel(IMongoModelBuilder modelBuilder) protected internal override void CreateModel(IMongoModelBuilder modelBuilder)
{ {
base.CreateModel(modelBuilder); base.CreateModel(modelBuilder);

67
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/AppEntityWithNavigations.cs

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Values;
namespace Volo.Abp.TestApp.Domain;
public class AppEntityWithNavigations : AggregateRoot<Guid>
{
protected AppEntityWithNavigations()
{
}
public AppEntityWithNavigations(Guid id, string name)
: base(id)
{
Name = name;
FullName = name;
}
public string Name { get; set; }
public string FullName { get; set; }
public AppEntityWithValueObjectAddress AppEntityWithValueObjectAddress { get; set; }
public virtual AppEntityWithNavigationChildOneToOne OneToOne { get; set; }
public virtual List<AppEntityWithNavigationChildOneToMany> OneToMany { get; set; }
public virtual List<AppEntityWithNavigationChildManyToMany> ManyToMany { get; set; }
}
public class AppEntityWithValueObjectAddress : ValueObject
{
public AppEntityWithValueObjectAddress(string country)
{
Country = country;
}
public string Country { get; set; }
protected override IEnumerable<object> GetAtomicValues()
{
yield return Country;
}
}
public class AppEntityWithNavigationChildOneToOne : Entity<Guid>
{
public string ChildName { get; set; }
}
public class AppEntityWithNavigationChildOneToMany : Entity<Guid>
{
public Guid AppEntityWithNavigationId { get; set; }
public string ChildName { get; set; }
}
public class AppEntityWithNavigationChildManyToMany : Entity<Guid>
{
public string ChildName { get; set; }
}

227
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Linq; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly; using Shouldly;
using Volo.Abp.Domain.Entities.Events; using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
@ -17,12 +18,14 @@ public abstract class DomainEvents_Tests<TStartupModule> : TestAppTestBase<TStar
where TStartupModule : IAbpModule where TStartupModule : IAbpModule
{ {
protected readonly IRepository<Person, Guid> PersonRepository; protected readonly IRepository<Person, Guid> PersonRepository;
protected readonly IRepository<AppEntityWithNavigations, Guid> AppEntityWithNavigationsRepository;
protected readonly ILocalEventBus LocalEventBus; protected readonly ILocalEventBus LocalEventBus;
protected readonly IDistributedEventBus DistributedEventBus; protected readonly IDistributedEventBus DistributedEventBus;
protected DomainEvents_Tests() protected DomainEvents_Tests()
{ {
PersonRepository = GetRequiredService<IRepository<Person, Guid>>(); PersonRepository = GetRequiredService<IRepository<Person, Guid>>();
AppEntityWithNavigationsRepository = GetRequiredService<IRepository<AppEntityWithNavigations, Guid>>();
LocalEventBus = GetRequiredService<ILocalEventBus>(); LocalEventBus = GetRequiredService<ILocalEventBus>();
DistributedEventBus = GetRequiredService<IDistributedEventBus>(); DistributedEventBus = GetRequiredService<IDistributedEventBus>();
} }
@ -173,6 +176,125 @@ public abstract class DomainEvents_Tests<TStartupModule> : TestAppTestBase<TStar
isDistributedEventTriggered.ShouldBeTrue(); isDistributedEventTriggered.ShouldBeTrue();
} }
[Fact]
public async Task Should_Trigger_Domain_Events_For_Aggregate_Root_When_Navigation_Changes_Tests()
{
var entityId = Guid.NewGuid();
await AppEntityWithNavigationsRepository.InsertAsync(new AppEntityWithNavigations(entityId, "TestEntity"));
var entityUpdatedEventTriggered = false;
LocalEventBus.Subscribe<EntityUpdatedEventData<AppEntityWithNavigations>>(data =>
{
entityUpdatedEventTriggered = !entityUpdatedEventTriggered;
return Task.CompletedTask;
});
// Test with simple property
await WithUnitOfWorkAsync(async () =>
{
var entity = await AppEntityWithNavigationsRepository.GetAsync(entityId);
entity.Name = Guid.NewGuid().ToString();
await AppEntityWithNavigationsRepository.UpdateAsync(entity);
});
entityUpdatedEventTriggered.ShouldBeTrue();
// Test with value object
entityUpdatedEventTriggered = false;
await WithUnitOfWorkAsync(async () =>
{
var entity = await AppEntityWithNavigationsRepository.GetAsync(entityId);
entity.AppEntityWithValueObjectAddress = new AppEntityWithValueObjectAddress("Turkey");
await AppEntityWithNavigationsRepository.UpdateAsync(entity);
});
entityUpdatedEventTriggered.ShouldBeTrue();
entityUpdatedEventTriggered = false;
await WithUnitOfWorkAsync(async () =>
{
var entity = await AppEntityWithNavigationsRepository.GetAsync(entityId);
entity.AppEntityWithValueObjectAddress = null;
await AppEntityWithNavigationsRepository.UpdateAsync(entity);
});
entityUpdatedEventTriggered.ShouldBeTrue();
// Test with one to one
entityUpdatedEventTriggered = false;
await WithUnitOfWorkAsync(async () =>
{
var entity = await AppEntityWithNavigationsRepository.GetAsync(entityId);
entity.OneToOne = new AppEntityWithNavigationChildOneToOne
{
ChildName = "ChildName"
};
await AppEntityWithNavigationsRepository.UpdateAsync(entity);
});
entityUpdatedEventTriggered.ShouldBeTrue();
entityUpdatedEventTriggered = false;
await WithUnitOfWorkAsync(async () =>
{
var entity = await AppEntityWithNavigationsRepository.GetAsync(entityId);
entity.OneToOne = null;
await AppEntityWithNavigationsRepository.UpdateAsync(entity);
});
// https://github.com/dotnet/efcore/issues/24076#issuecomment-1996623874
// entityUpdatedEventTriggered.ShouldBeTrue();
// Test with one to many
entityUpdatedEventTriggered = false;
await WithUnitOfWorkAsync(async () =>
{
var entity = await AppEntityWithNavigationsRepository.GetAsync(entityId);
entity.OneToMany = new List<AppEntityWithNavigationChildOneToMany>()
{
new AppEntityWithNavigationChildOneToMany
{
AppEntityWithNavigationId = entity.Id,
ChildName = "ChildName1"
}
};
await AppEntityWithNavigationsRepository.UpdateAsync(entity);
});
entityUpdatedEventTriggered.ShouldBeTrue();
entityUpdatedEventTriggered = false;
await WithUnitOfWorkAsync(async () =>
{
var entity = await AppEntityWithNavigationsRepository.GetAsync(entityId);
entity.OneToMany.Clear();
await AppEntityWithNavigationsRepository.UpdateAsync(entity);
});
// https://github.com/dotnet/efcore/issues/24076#issuecomment-1996623874
// entityUpdatedEventTriggered.ShouldBeTrue();
// Test with many to many
entityUpdatedEventTriggered = false;
await WithUnitOfWorkAsync(async () =>
{
var entity = await AppEntityWithNavigationsRepository.GetAsync(entityId);
entity.ManyToMany = new List<AppEntityWithNavigationChildManyToMany>()
{
new AppEntityWithNavigationChildManyToMany
{
ChildName = "ChildName1"
}
};
await AppEntityWithNavigationsRepository.UpdateAsync(entity);
});
entityUpdatedEventTriggered.ShouldBeTrue();
entityUpdatedEventTriggered = false;
await WithUnitOfWorkAsync(async () =>
{
var entity = await AppEntityWithNavigationsRepository.GetAsync(entityId);
entity.ManyToMany.Clear();
await AppEntityWithNavigationsRepository.UpdateAsync(entity);
});
entityUpdatedEventTriggered.ShouldBeTrue();
}
private class MyCustomEventData private class MyCustomEventData
{ {
public string Value { get; set; } public string Value { get; set; }
@ -183,3 +305,106 @@ public abstract class DomainEvents_Tests<TStartupModule> : TestAppTestBase<TStar
public string Value { get; set; } public string Value { get; set; }
} }
} }
public abstract class AbpEntityChangeOptions_DomainEvents_Tests<TStartupModule> : TestAppTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
protected readonly IRepository<AppEntityWithNavigations, Guid> AppEntityWithNavigationsRepository;
protected readonly ILocalEventBus LocalEventBus;
protected AbpEntityChangeOptions_DomainEvents_Tests()
{
AppEntityWithNavigationsRepository = GetRequiredService<IRepository<AppEntityWithNavigations, Guid>>();
LocalEventBus = GetRequiredService<ILocalEventBus>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
services.Configure<AbpEntityChangeOptions>(options =>
{
options.PublishEntityUpdatedEventWhenNavigationChanges = false;
});
base.AfterAddApplication(services);
}
[Fact]
public async Task Should_Not_Trigger_Domain_Events_For_Aggregate_Root_When_Navigation_Changes_Tests()
{
var entityId = Guid.NewGuid();
await AppEntityWithNavigationsRepository.InsertAsync(new AppEntityWithNavigations(entityId, "TestEntity"));
var entityUpdatedEventTriggered = false;
LocalEventBus.Subscribe<EntityUpdatedEventData<AppEntityWithNavigations>>(data =>
{
entityUpdatedEventTriggered = !entityUpdatedEventTriggered;
return Task.CompletedTask;
});
// Test with simple property
await WithUnitOfWorkAsync(async () =>
{
var entity = await AppEntityWithNavigationsRepository.GetAsync(entityId);
entity.Name = Guid.NewGuid().ToString();
await AppEntityWithNavigationsRepository.UpdateAsync(entity);
});
entityUpdatedEventTriggered.ShouldBeTrue();
// Test with value object
entityUpdatedEventTriggered = false;
await WithUnitOfWorkAsync(async () =>
{
var entity = await AppEntityWithNavigationsRepository.GetAsync(entityId);
entity.AppEntityWithValueObjectAddress = new AppEntityWithValueObjectAddress("Turkey");
await AppEntityWithNavigationsRepository.UpdateAsync(entity);
});
entityUpdatedEventTriggered.ShouldBeFalse();
// Test with one to one
entityUpdatedEventTriggered = false;
await WithUnitOfWorkAsync(async () =>
{
var entity = await AppEntityWithNavigationsRepository.GetAsync(entityId);
entity.OneToOne = new AppEntityWithNavigationChildOneToOne
{
ChildName = "ChildName"
};
await AppEntityWithNavigationsRepository.UpdateAsync(entity);
});
entityUpdatedEventTriggered.ShouldBeFalse();
// Test with one to many
entityUpdatedEventTriggered = false;
await WithUnitOfWorkAsync(async () =>
{
var entity = await AppEntityWithNavigationsRepository.GetAsync(entityId);
entity.OneToMany = new List<AppEntityWithNavigationChildOneToMany>()
{
new AppEntityWithNavigationChildOneToMany
{
AppEntityWithNavigationId = entity.Id,
ChildName = "ChildName1"
}
};
await AppEntityWithNavigationsRepository.UpdateAsync(entity);
});
entityUpdatedEventTriggered.ShouldBeFalse();
// Test with many to many
entityUpdatedEventTriggered = false;
await WithUnitOfWorkAsync(async () =>
{
var entity = await AppEntityWithNavigationsRepository.GetAsync(entityId);
entity.ManyToMany = new List<AppEntityWithNavigationChildManyToMany>()
{
new AppEntityWithNavigationChildManyToMany
{
ChildName = "ChildName1"
}
};
await AppEntityWithNavigationsRepository.UpdateAsync(entity);
});
entityUpdatedEventTriggered.ShouldBeFalse();
}
}

3
modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_User_Change_Event_Tests.cs

@ -45,8 +45,11 @@ public class Distributed_User_Change_Event_Tests : AbpIdentityDomainTestBase
[Fact] [Fact]
public async Task Should_Trigger_Distributed_EntityUpdated_Event() public async Task Should_Trigger_Distributed_EntityUpdated_Event()
{ {
_testCounter.ResetCount("EntityUpdatedEto<UserEto>");
using (var uow = _unitOfWorkManager.Begin()) using (var uow = _unitOfWorkManager.Begin())
{ {
_testCounter.GetValue("EntityUpdatedEto<UserEto>").ShouldBe(0);
var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash"));
await _userManager.SetEmailAsync(user, "john.nash_UPDATED@abp.io"); await _userManager.SetEmailAsync(user, "john.nash_UPDATED@abp.io");

Loading…
Cancel
Save