Browse Source

Merge pull request #19486 from abpframework/auto-merge/rel-8-0/2620

Merge branch rel-8.1 with rel-8.0
pull/19487/head
maliming 3 years ago
committed by GitHub
parent
commit
b9f115302c
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 10
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/AbpEntityChangeOptions.cs
  2. 31
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs
  3. 163
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEfCoreNavigationHelper.cs
  4. 20
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEntityEntryNavigationProperty.cs
  5. 20
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs
  6. 3
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/IEntityHistoryHelper.cs
  7. 6
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/NullEntityHistoryHelper.cs
  8. 2
      framework/src/Volo.Abp.TestBase/Volo/Abp/Testing/Utils/ITestCounter.cs
  9. 8
      framework/src/Volo.Abp.TestBase/Volo/Abp/Testing/Utils/TestCounter.cs
  10. 1
      framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs
  11. 7
      framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkEventRecord.cs
  12. 4
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AbpAuditingTestModule.cs
  13. 13
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/Entities/AppEntityWithNavigations.cs
  14. 3
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/EntityFrameworkCore/AbpAuditingTestDbContext.cs
  15. 177
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs
  16. 5
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs
  17. 4
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DomainEvents/DomainEvents_Tests.cs
  18. 11
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs
  19. 11
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs
  20. 3
      framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/TestApp/MemoryDb/TestAppMemoryDbContext.cs
  21. 7
      framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Serializer/MongoDB_DateTimeKind_Tests.cs
  22. 2
      framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/ITestAppMongoDbContext.cs
  23. 4
      framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs
  24. 76
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/AppEntityWithNavigations.cs
  25. 225
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs
  26. 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;
}

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

@ -12,6 +12,7 @@ using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Auditing;
@ -20,6 +21,7 @@ using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EntityFrameworkCore.ChangeTrackers;
using Volo.Abp.EntityFrameworkCore.EntityHistory;
using Volo.Abp.EntityFrameworkCore.Modeling;
using Volo.Abp.EntityFrameworkCore.ValueConverters;
@ -53,6 +55,8 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
public IEntityChangeEventHelper EntityChangeEventHelper => LazyServiceProvider.LazyGetService<IEntityChangeEventHelper>(NullEntityChangeEventHelper.Instance);
public IOptions<AbpEntityChangeOptions> EntityChangeOptions => LazyServiceProvider.LazyGetRequiredService<IOptions<AbpEntityChangeOptions>>();
public IAuditPropertySetter AuditPropertySetter => LazyServiceProvider.LazyGetRequiredService<IAuditPropertySetter>();
public IEntityHistoryHelper EntityHistoryHelper => LazyServiceProvider.LazyGetService<IEntityHistoryHelper>(NullEntityHistoryHelper.Instance);
@ -69,6 +73,8 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
public ILogger<AbpDbContext<TDbContext>> Logger => LazyServiceProvider.LazyGetService<ILogger<AbpDbContext<TDbContext>>>(NullLogger<AbpDbContext<TDbContext>>.Instance);
public AbpEfCoreNavigationHelper AbpEfCoreNavigationHelper => LazyServiceProvider.LazyGetRequiredService<AbpEfCoreNavigationHelper>();
private static readonly MethodInfo ConfigureBasePropertiesMethodInfo
= typeof(AbpDbContext<TDbContext>)
.GetMethod(
@ -160,6 +166,7 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
List<EntityChangeInfo>? entityChangeList = null;
if (auditLog != null)
{
EntityHistoryHelper.InitializeNavigationHelper(AbpEfCoreNavigationHelper);
entityChangeList = EntityHistoryHelper.CreateChangeList(ChangeTracker.Entries().ToList());
}
@ -251,12 +258,14 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
protected virtual void ChangeTracker_Tracked(object? sender, EntityTrackedEventArgs e)
{
AbpEfCoreNavigationHelper.ChangeTracker_Tracked(ChangeTracker, sender, e);
FillExtraPropertiesForTrackedEntities(e);
PublishEventsForTrackedEntity(e.Entry);
}
protected virtual void ChangeTracker_StateChanged(object? sender, EntityStateChangedEventArgs e)
{
AbpEfCoreNavigationHelper.ChangeTracker_StateChanged(ChangeTracker, sender, e);
PublishEventsForTrackedEntity(e.Entry);
}
@ -306,7 +315,7 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
}
}
private void PublishEventsForTrackedEntity(EntityEntry entry)
protected virtual void PublishEventsForTrackedEntity(EntityEntry entry)
{
switch (entry.State)
{
@ -314,9 +323,10 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
ApplyAbpConceptsForAddedEntity(entry);
EntityChangeEventHelper.PublishEntityCreatedEvent(entry.Entity);
break;
case EntityState.Modified:
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 || x.Metadata.ValueGenerated == ValueGenerated.OnAdd)))
{
if (entry.Entity is ISoftDelete && entry.Entity.As<ISoftDelete>().IsDeleted)
{
@ -327,13 +337,28 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
EntityChangeEventHelper.PublishEntityUpdatedEvent(entry.Entity);
}
}
break;
case EntityState.Deleted:
ApplyAbpConceptsForDeletedEntity(entry);
EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity);
break;
}
if (EntityChangeOptions.Value.PublishEntityUpdatedEventWhenNavigationChanges)
{
foreach (var entityEntry in ChangeTracker.Entries().Where(x => x.State == EntityState.Unchanged && AbpEfCoreNavigationHelper.IsEntityEntryNavigationChanged(x)))
{
if (entityEntry.Entity is ISoftDelete && entityEntry.Entity.As<ISoftDelete>().IsDeleted)
{
EntityChangeEventHelper.PublishEntityDeletedEvent(entityEntry.Entity);
}
else
{
EntityChangeEventHelper.PublishEntityUpdatedEvent(entityEntry.Entity);
}
}
}
}
protected virtual void HandlePropertiesBeforeSave()

163
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEfCoreNavigationHelper.cs

@ -0,0 +1,163 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.EntityFrameworkCore.ChangeTrackers;
/// <summary>
/// Refactor this class after EF Core supports this case.
/// https://github.com/dotnet/efcore/issues/24076#issuecomment-1996623874
/// </summary>
public class AbpEfCoreNavigationHelper : ITransientDependency
{
private Dictionary<string, List<AbpEntityEntryNavigationProperty>> EntityEntryNavigationProperties { get; } = new ();
public virtual void ChangeTracker_Tracked(ChangeTracker changeTracker, object? sender, EntityTrackedEventArgs e)
{
foreach (var entry in changeTracker.Entries())
{
EntityEntryTrackedOrStateChanged(entry);
}
}
public virtual void ChangeTracker_StateChanged(ChangeTracker changeTracker, object? sender, EntityStateChangedEventArgs e)
{
foreach (var entry in changeTracker.Entries())
{
EntityEntryTrackedOrStateChanged(entry);
}
}
private void EntityEntryTrackedOrStateChanged(EntityEntry entityEntry)
{
if (entityEntry.State != EntityState.Unchanged)
{
return;
}
var entryId = GetEntityId(entityEntry);
if (entryId == null)
{
return;
}
var navigationProperties = EntityEntryNavigationProperties.GetOrAdd(entryId, () => new List<AbpEntityEntryNavigationProperty>());
var index = 0;
foreach (var navigationEntry in entityEntry.Navigations.Where(navigation => !navigation.IsModified))
{
if (!navigationEntry.IsLoaded)
{
index++;
continue;
}
var currentValue = navigationEntry.CurrentValue;
if (navigationEntry.CurrentValue is ICollection collection)
{
currentValue = collection.Cast<object?>().ToList();
}
var navigationProperty = navigationProperties.FirstOrDefault(x => x.Index == index);
if (navigationProperty != null)
{
if (!navigationProperty.IsChanged && (navigationProperty.Value == null || IsCollectionAndEmpty(navigationProperty.Value)))
{
navigationProperty.Value = currentValue;
navigationProperty.IsChanged = currentValue != null && !IsCollectionAndEmpty(currentValue);
}
if (!navigationProperty.IsChanged && navigationProperty.Value != null && !IsCollectionAndEmpty(navigationProperty.Value))
{
navigationProperty.Value = currentValue;
navigationProperty.IsChanged = currentValue == null || IsCollectionAndEmpty(currentValue);
}
}
else
{
navigationProperties.Add(new AbpEntityEntryNavigationProperty(index, navigationEntry.Metadata.Name, currentValue, false));
}
index++;
}
}
public bool IsEntityEntryNavigationChanged(EntityEntry entityEntry)
{
if (entityEntry.State == EntityState.Modified)
{
return true;
}
var entryId = GetEntityId(entityEntry);
if (entryId == null)
{
return false;
}
var index = 0;
foreach (var navigationEntry in entityEntry.Navigations)
{
if (navigationEntry.IsModified || (navigationEntry is ReferenceEntry && navigationEntry.As<ReferenceEntry>().TargetEntry?.State == EntityState.Modified))
{
return true;
}
EntityEntryTrackedOrStateChanged(entityEntry);
if (EntityEntryNavigationProperties.TryGetValue(entryId, out var navigationProperties))
{
var navigationProperty = navigationProperties.FirstOrDefault(x => x.Index == index);
if (navigationProperty != null && navigationProperty.IsChanged)
{
return true;
}
}
index++;
}
return false;
}
public bool IsEntityEntryNavigationChanged(NavigationEntry navigationEntry, int index)
{
if (navigationEntry.IsModified || (navigationEntry is ReferenceEntry && navigationEntry.As<ReferenceEntry>().TargetEntry?.State == EntityState.Modified))
{
return true;
}
var entryId = GetEntityId(navigationEntry.EntityEntry);
if (entryId == null)
{
return false;
}
if (EntityEntryNavigationProperties.TryGetValue(entryId, out var navigationProperties))
{
var navigationProperty = navigationProperties.FirstOrDefault(x => x.Index == index);
if (navigationProperty != null && navigationProperty.IsChanged)
{
return true;
}
}
return false;
}
private string? GetEntityId(EntityEntry entityEntry)
{
return entityEntry.Entity is IEntity entryEntity && entryEntity.GetKeys().Length == 1
? entryEntity.GetKeys().FirstOrDefault()?.ToString()
: null;
}
private bool IsCollectionAndEmpty(object? value)
{
return value is ICollection && value is ICollection collection && collection.Count == 0;
}
}

20
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEntityEntryNavigationProperty.cs

@ -0,0 +1,20 @@
namespace Volo.Abp.EntityFrameworkCore.ChangeTrackers;
public class AbpEntityEntryNavigationProperty
{
public int Index { get; set; }
public string Name { get; set; }
public object? Value { get; set; }
public bool IsChanged { get; set; }
public AbpEntityEntryNavigationProperty(int index, string name, object? value, bool isChanged)
{
Index = index;
Name = name;
Value = value;
IsChanged = isChanged;
}
}

20
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs

@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.Extensions.Logging;
@ -13,6 +12,7 @@ using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Values;
using Volo.Abp.EntityFrameworkCore.ChangeTrackers;
using Volo.Abp.Json;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection;
@ -30,6 +30,8 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
protected IAuditingHelper AuditingHelper { get; }
protected IClock Clock { get; }
protected AbpEfCoreNavigationHelper? AbpEfCoreNavigationHelper { get; set; }
public EntityHistoryHelper(
IAuditingStore auditingStore,
IOptions<AbpAuditingOptions> options,
@ -46,6 +48,11 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
Logger = NullLogger<EntityHistoryHelper>.Instance;
}
public void InitializeNavigationHelper(AbpEfCoreNavigationHelper abpEfCoreNavigationHelper)
{
AbpEfCoreNavigationHelper = abpEfCoreNavigationHelper;
}
public virtual List<EntityChangeInfo> CreateChangeList(ICollection<EntityEntry> entityEntries)
{
var list = new List<EntityChangeInfo>();
@ -186,11 +193,12 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
}
}
if (Options.SaveEntityHistoryWhenNavigationChanges && entityEntry.State == EntityState.Unchanged)
if (entityEntry.State == EntityState.Unchanged && Options.SaveEntityHistoryWhenNavigationChanges && AbpEfCoreNavigationHelper != null)
{
var index = 0;
foreach (var navigation in entityEntry.Navigations)
{
if (navigation.IsModified || (navigation is ReferenceEntry && navigation.As<ReferenceEntry>().TargetEntry?.State == EntityState.Modified))
if (navigation.IsModified || AbpEfCoreNavigationHelper.IsEntityEntryNavigationChanged(navigation, index))
{
propertyChanges.Add(new EntityPropertyChangeInfo
{
@ -198,6 +206,8 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
PropertyTypeFullName = navigation.Metadata.ClrType.GetFirstGenericArgumentIfNullable().FullName!
});
}
index++;
}
}
@ -245,9 +255,7 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
protected virtual bool HasNavigationPropertiesChanged(EntityEntry entityEntry)
{
return Options.SaveEntityHistoryWhenNavigationChanges && entityEntry.State == EntityState.Unchanged &&
(entityEntry.Navigations.Any(navigationEntry => navigationEntry.IsModified) ||
entityEntry.Navigations.Where(x => x is ReferenceEntry).Cast<ReferenceEntry>().Any(x => x.TargetEntry != null && x.TargetEntry.State == EntityState.Modified));
return entityEntry.State == EntityState.Unchanged && Options.SaveEntityHistoryWhenNavigationChanges && AbpEfCoreNavigationHelper != null && AbpEfCoreNavigationHelper.IsEntityEntryNavigationChanged(entityEntry);
}
protected virtual bool ShouldSavePropertyHistory(PropertyEntry propertyEntry, bool defaultValue)

3
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/IEntityHistoryHelper.cs

@ -1,11 +1,14 @@
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Volo.Abp.Auditing;
using Volo.Abp.EntityFrameworkCore.ChangeTrackers;
namespace Volo.Abp.EntityFrameworkCore.EntityHistory;
public interface IEntityHistoryHelper
{
void InitializeNavigationHelper(AbpEfCoreNavigationHelper abpEfCoreNavigationHelper);
List<EntityChangeInfo> CreateChangeList(ICollection<EntityEntry> entityEntries);
void UpdateChangeList(List<EntityChangeInfo> entityChanges);

6
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/NullEntityHistoryHelper.cs

@ -1,6 +1,7 @@
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Volo.Abp.Auditing;
using Volo.Abp.EntityFrameworkCore.ChangeTrackers;
namespace Volo.Abp.EntityFrameworkCore.EntityHistory;
@ -13,6 +14,11 @@ public class NullEntityHistoryHelper : IEntityHistoryHelper
}
public void InitializeNavigationHelper(AbpEfCoreNavigationHelper abpEfCoreNavigationHelper)
{
}
public List<EntityChangeInfo> CreateChangeList(ICollection<EntityEntry> entityEntries)
{
return new List<EntityChangeInfo>();

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

@ -9,4 +9,6 @@ public interface ITestCounter
int Increment(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);
}
}
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
{
eventRecord.SetOrder(eventRecords[foundIndex].EventOrder);
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 long EventOrder { get; }
public long EventOrder { get; protected set; }
public bool UseOutbox { get; }
@ -29,4 +29,9 @@ public class UnitOfWorkEventRecord
EventOrder = eventOrder;
UseOutbox = useOutbox;
}
public void SetOrder(long order)
{
EventOrder = order;
}
}

4
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AbpAuditingTestModule.cs

@ -24,6 +24,10 @@ public class AbpAuditingTestModule : AbpModule
context.Services.AddAbpDbContext<AbpAuditingTestDbContext>(options =>
{
options.AddDefaultRepositories(true);
options.Entity<AppEntityWithNavigations>(opt =>
{
opt.DefaultWithDetailsFunc = q => q.Include(p => p.OneToOne).Include(p => p.OneToMany).Include(p => p.ManyToMany);
});
});
var sqliteConnection = CreateDatabaseAndGetConnection();

13
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/Entities/AppEntityWithNavigations.cs

@ -23,6 +23,8 @@ public class AppEntityWithNavigations : AggregateRoot<Guid>
public string FullName { get; set; }
public AppEntityWithValueObjectAddress AppEntityWithValueObjectAddress { get; set; }
public virtual AppEntityWithNavigationChildOneToOne OneToOne { get; set; }
public virtual List<AppEntityWithNavigationChildOneToMany> OneToMany { get; set; }
@ -45,7 +47,16 @@ public class AppEntityWithNavigationChildOneToMany : Entity<Guid>
}
[Audited]
public class AppEntityWithNavigationChildManyToMany : Entity<Guid>
public class AppEntityWithNavigationChildManyToMany : AggregateRoot<Guid>
{
public string ChildName { get; set; }
public virtual List<AppEntityWithNavigations> ManyToMany { get; set; }
}
public class AppEntityWithNavigationsAndAppEntityWithNavigationChildManyToMany
{
public Guid AppEntityWithNavigationsId { get; set; }
public Guid AppEntityWithNavigationChildManyToManyId { get; set; }
}

3
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/EntityFrameworkCore/AbpAuditingTestDbContext.cs

@ -48,9 +48,10 @@ public class AbpAuditingTestDbContext : AbpDbContext<AbpAuditingTestDbContext>
modelBuilder.Entity<AppEntityWithNavigations>(b =>
{
b.ConfigureByConvention();
b.OwnsOne(x => x.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();
b.HasMany(x => x.ManyToMany).WithMany(x => x.ManyToMany).UsingEntity<AppEntityWithNavigationsAndAppEntityWithNavigationChildManyToMany>();
});
}

177
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs

@ -385,10 +385,10 @@ public class Auditing_Tests : AbpAuditingTestBase
#pragma warning disable 4014
AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 3 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Created &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithValueObjectAddress).FullName &&
x.EntityChanges[1].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithValueObject).FullName &&
x.EntityChanges[0].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithValueObject).FullName &&
x.EntityChanges[1].ChangeType == EntityChangeType.Created &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithValueObjectAddress).FullName &&
x.EntityChanges[2].ChangeType == EntityChangeType.Deleted &&
x.EntityChanges[2].EntityTypeFullName == typeof(AppEntityWithValueObjectAddress).FullName));
AuditingStore.ClearReceivedCalls();
@ -411,16 +411,16 @@ public class Auditing_Tests : AbpAuditingTestBase
#pragma warning disable 4014
AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 2 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithValueObjectAddress).FullName &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithValueObject).FullName &&
x.EntityChanges[0].PropertyChanges.Count == 1 &&
x.EntityChanges[0].PropertyChanges[0].PropertyName == nameof(AppEntityWithValueObjectAddress.Country) &&
x.EntityChanges[0].PropertyChanges[0].OriginalValue == "\"England\"" &&
x.EntityChanges[0].PropertyChanges[0].NewValue == "\"Germany\"" &&
x.EntityChanges[0].PropertyChanges[0].PropertyName == nameof(AppEntityWithValueObject.AppEntityWithValueObjectAddress) &&
x.EntityChanges[1].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithValueObject).FullName &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithValueObjectAddress).FullName &&
x.EntityChanges[1].PropertyChanges.Count == 1 &&
x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithValueObject.AppEntityWithValueObjectAddress)));
x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithValueObjectAddress.Country) &&
x.EntityChanges[1].PropertyChanges[0].OriginalValue == "\"England\"" &&
x.EntityChanges[1].PropertyChanges[0].NewValue == "\"Germany\""));
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
@ -439,11 +439,16 @@ public class Auditing_Tests : AbpAuditingTestBase
}
#pragma warning disable 4014
AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 1 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Deleted &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithValueObjectAddress).FullName &&
x.EntityChanges[0].PropertyChanges.Count == 2 &&
x.EntityChanges[0].PropertyChanges.All(p => p.NewValue == null)));
AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 2 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithValueObject).FullName &&
x.EntityChanges[0].PropertyChanges.Count == 1 &&
x.EntityChanges[0].PropertyChanges[0].PropertyName == nameof(AppEntityWithValueObject.AppEntityWithValueObjectAddress) &&
x.EntityChanges[1].ChangeType == EntityChangeType.Deleted &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithValueObjectAddress).FullName &&
x.EntityChanges[1].PropertyChanges.Count == 2 &&
x.EntityChanges[1].PropertyChanges.All(p => p.NewValue == null)));
#pragma warning restore 4014
}
@ -511,6 +516,33 @@ public class Auditing_Tests : AbpAuditingTestBase
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())
{
var entity = await repository.GetAsync(entityId);
entity.OneToOne = null;
await repository.UpdateAsync(entity);
await uow.CompleteAsync();
await scope.SaveAsync();
}
}
#pragma warning disable 4014
AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 2 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Deleted &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithNavigationChildOneToOne).FullName &&
x.EntityChanges[1].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName &&
x.EntityChanges[1].PropertyChanges.Count == 1 &&
x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.OneToOne) &&
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(AppEntityWithNavigationChildOneToOne).FullName));
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())
@ -544,6 +576,32 @@ public class Auditing_Tests : AbpAuditingTestBase
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())
{
var entity = await repository.GetAsync(entityId);
entity.OneToMany = null;
await repository.UpdateAsync(entity);
await uow.CompleteAsync();
await scope.SaveAsync();
}
}
#pragma warning disable 4014
AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 2 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Deleted &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithNavigationChildOneToMany).FullName &&
x.EntityChanges[1].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName &&
x.EntityChanges[1].PropertyChanges.Count == 1 &&
x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.OneToMany) &&
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildOneToMany>).FullName));
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())
@ -574,6 +632,36 @@ public class Auditing_Tests : AbpAuditingTestBase
x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.ManyToMany) &&
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildManyToMany>).FullName));
#pragma warning restore 4014
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())
{
var entity = await repository.GetAsync(entityId);
entity.ManyToMany.Clear();
await repository.UpdateAsync(entity);
await uow.CompleteAsync();
await scope.SaveAsync();
}
}
#pragma warning disable 4014
AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 2 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName &&
x.EntityChanges[0].PropertyChanges.Count == 1 &&
x.EntityChanges[0].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.ManyToMany) &&
x.EntityChanges[0].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildManyToMany>).FullName &&
x.EntityChanges[1].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigationChildManyToMany).FullName &&
x.EntityChanges[1].PropertyChanges.Count == 1 &&
x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigationChildManyToMany.ManyToMany) &&
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigations>).FullName));
#pragma warning restore 4014
}
}
@ -648,10 +736,10 @@ public class Auditing_SaveEntityHistoryWhenNavigationChanges_Tests : AbpAuditing
#pragma warning disable 4014
AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 3 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Created &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithValueObjectAddress).FullName &&
x.EntityChanges[1].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithValueObject).FullName &&
x.EntityChanges[0].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithValueObject).FullName &&
x.EntityChanges[1].ChangeType == EntityChangeType.Created &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithValueObjectAddress).FullName &&
x.EntityChanges[2].ChangeType == EntityChangeType.Deleted &&
x.EntityChanges[2].EntityTypeFullName == typeof(AppEntityWithValueObjectAddress).FullName));
AuditingStore.ClearReceivedCalls();
@ -767,6 +855,31 @@ public class Auditing_SaveEntityHistoryWhenNavigationChanges_Tests : AbpAuditing
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())
{
var entity = await repository.GetAsync(entityId);
entity.OneToOne = null;
await repository.UpdateAsync(entity);
await uow.CompleteAsync();
await scope.SaveAsync();
}
}
#pragma warning disable 4014
AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 1 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Deleted &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithNavigationChildOneToOne).FullName &&
x.EntityChanges[0].PropertyChanges.Count == 1 &&
x.EntityChanges[0].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigationChildOneToOne.ChildName) &&
x.EntityChanges[0].PropertyChanges[0].PropertyTypeFullName == typeof(string).FullName));
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())
@ -800,6 +913,32 @@ public class Auditing_SaveEntityHistoryWhenNavigationChanges_Tests : AbpAuditing
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())
{
var entity = await repository.GetAsync(entityId);
entity.OneToMany.Clear();
await repository.UpdateAsync(entity);
await uow.CompleteAsync();
await scope.SaveAsync();
}
}
#pragma warning disable 4014
AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 1 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Deleted &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithNavigationChildOneToMany).FullName &&
x.EntityChanges[0].PropertyChanges.Count == 2 &&
x.EntityChanges[0].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigationChildOneToMany.AppEntityWithNavigationId) &&
x.EntityChanges[0].PropertyChanges[0].PropertyTypeFullName == typeof(Guid).FullName &&
x.EntityChanges[0].PropertyChanges[1].PropertyName == nameof(AppEntityWithNavigationChildOneToMany.ChildName) &&
x.EntityChanges[0].PropertyChanges[1].PropertyTypeFullName == typeof(string).FullName));
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())

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);
});
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 =>

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 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<AppEntityWithNavigations> AppEntityWithNavigations { get; set; }
public TestMigrationsDbContext(DbContextOptions<TestMigrationsDbContext> options)
: base(options)
{
@ -64,5 +66,14 @@ public class TestMigrationsDbContext : AbpDbContext<TestMigrationsDbContext>
{
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(x => x.ManyToMany).UsingEntity<AppEntityWithNavigationsAndAppEntityWithNavigationChildManyToMany>();
});
}
}

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<AppEntityWithNavigations> AppEntityWithNavigations { get; set; }
public TestAppDbContext(DbContextOptions<TestAppDbContext> options)
: base(options)
{
@ -92,6 +94,15 @@ public class TestAppDbContext : AbpDbContext<TestAppDbContext>, IThirdDbContext,
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(x => x.ManyToMany).UsingEntity<AppEntityWithNavigationsAndAppEntityWithNavigationChildManyToMany>();
});
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 = {
typeof(Person),
typeof(EntityWithIntPk),
typeof(Product)
typeof(Product),
typeof(AppEntityWithNavigations)
};
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.
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)
{
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
{
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
{
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<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<FourthDbContextDummyEntity> FourthDummyEntities => Collection<FourthDbContextDummyEntity>();
public IMongoCollection<Product> Products => Collection<Product>();
public IMongoCollection<AppEntityWithNavigations> AppEntityWithNavigations => Collection<AppEntityWithNavigations>();
protected internal override void CreateModel(IMongoModelBuilder modelBuilder)
{
base.CreateModel(modelBuilder);

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

@ -0,0 +1,76 @@
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 : AggregateRoot<Guid>
{
public string ChildName { get; set; }
public virtual List<AppEntityWithNavigations> ManyToMany { get; set; }
}
public class AppEntityWithNavigationsAndAppEntityWithNavigationChildManyToMany
{
public Guid AppEntityWithNavigationsId { get; set; }
public Guid AppEntityWithNavigationChildManyToManyId { get; set; }
}

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

@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Domain.Repositories;
@ -17,12 +18,14 @@ public abstract class DomainEvents_Tests<TStartupModule> : TestAppTestBase<TStar
where TStartupModule : IAbpModule
{
protected readonly IRepository<Person, Guid> PersonRepository;
protected readonly IRepository<AppEntityWithNavigations, Guid> AppEntityWithNavigationsRepository;
protected readonly ILocalEventBus LocalEventBus;
protected readonly IDistributedEventBus DistributedEventBus;
protected DomainEvents_Tests()
{
PersonRepository = GetRequiredService<IRepository<Person, Guid>>();
AppEntityWithNavigationsRepository = GetRequiredService<IRepository<AppEntityWithNavigations, Guid>>();
LocalEventBus = GetRequiredService<ILocalEventBus>();
DistributedEventBus = GetRequiredService<IDistributedEventBus>();
}
@ -173,6 +176,123 @@ public abstract class DomainEvents_Tests<TStartupModule> : TestAppTestBase<TStar
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);
});
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);
});
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
{
public string Value { get; set; }
@ -183,3 +303,106 @@ public abstract class DomainEvents_Tests<TStartupModule> : TestAppTestBase<TStar
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]
public async Task Should_Trigger_Distributed_EntityUpdated_Event()
{
_testCounter.ResetCount("EntityUpdatedEto<UserEto>");
using (var uow = _unitOfWorkManager.Begin())
{
_testCounter.GetValue("EntityUpdatedEto<UserEto>").ShouldBe(0);
var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash"));
await _userManager.SetEmailAsync(user, "john.nash_UPDATED@abp.io");

Loading…
Cancel
Save