Browse Source

Merge pull request #21873 from abpframework/21866

Get the before and after changes of navigation properties.
pull/21987/head
oykuermann 2 years ago
committed by GitHub
parent
commit
02bb30463f
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 24
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEfCoreNavigationHelper.cs
  2. 64
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEntityEntry.cs
  3. 47
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs
  4. 72
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs
  5. 2
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/en.json
  6. 39
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogEntityTypeFullNameConverter.cs
  7. 18
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogInfoToAuditLogConverter.cs
  8. 6
      modules/audit-logging/test/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests/Volo/Abp/AuditLogging/EntityFrameworkCore/AuditLogEntityTypeFullNameConverter_Tests.cs
  9. 9
      modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo/Abp/AuditLogging/MongoDB/AuditLogEntityTypeFullNameConverter_Tests.cs
  10. 46
      modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditLogEntityTypeFullNameConverter_Tests.cs

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

@ -31,6 +31,14 @@ public class AbpEfCoreNavigationHelper : ITransientDependency
protected virtual void EntityEntryTrackedOrStateChanged(EntityEntry entityEntry)
{
if (entityEntry.State is EntityState.Unchanged or EntityState.Modified)
{
foreach (var entry in EntityEntries.Values.Where(x => x.NavigationEntries.Any()))
{
entry.UpdateNavigationEntries();
}
}
if (entityEntry.State != EntityState.Unchanged)
{
return;
@ -189,6 +197,22 @@ public class AbpEfCoreNavigationHelper : ITransientDependency
return navigationEntryProperty != null && navigationEntryProperty.IsModified;
}
public virtual AbpNavigationEntry? GetNavigationEntry(EntityEntry entityEntry, int navigationEntryIndex)
{
var entryId = GetEntityEntryIdentity(entityEntry);
if (entryId == null)
{
return null;
}
if (!EntityEntries.TryGetValue(entryId, out var abpEntityEntry))
{
return null;
}
return abpEntityEntry.NavigationEntries.ElementAtOrDefault(navigationEntryIndex);
}
protected virtual string? GetEntityEntryIdentity(EntityEntry entityEntry)
{
if (entityEntry.Entity is IEntity entryEntity && entryEntity.GetKeys().Length == 1)

64
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEntityEntry.cs

@ -1,3 +1,4 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
@ -32,6 +33,49 @@ public class AbpEntityEntry
EntityEntry = entityEntry;
NavigationEntries = EntityEntry.Navigations.Select(x => new AbpNavigationEntry(x, x.Metadata.Name)).ToList();
}
public void UpdateNavigationEntries()
{
foreach (var navigationEntry in NavigationEntries)
{
if (IsModified ||
EntityEntry.State == EntityState.Modified ||
navigationEntry.IsModified ||
navigationEntry.NavigationEntry.IsModified)
{
continue;
}
var navigation = EntityEntry.Navigations.FirstOrDefault(n => n.Metadata.Name == navigationEntry.Name);
var currentValue = AbpNavigationEntry.GetOriginalValue(navigation?.CurrentValue);
if (currentValue == null)
{
continue;
}
switch (navigationEntry.OriginalValue)
{
case null:
navigationEntry.OriginalValue = currentValue;
break;
case IEnumerable originalValueCollection when currentValue is IEnumerable currentValueCollection:
{
var existingList = originalValueCollection.Cast<object?>().ToList();
var newList = currentValueCollection.Cast<object?>().ToList();
if (newList.Count > existingList.Count)
{
navigationEntry.OriginalValue = currentValue;
}
break;
}
default:
navigationEntry.OriginalValue = currentValue;
break;
}
}
}
}
public class AbpNavigationEntry
@ -42,9 +86,29 @@ public class AbpNavigationEntry
public bool IsModified { get; set; }
public List<object>? OriginalValue { get; set; }
public object? CurrentValue => NavigationEntry.CurrentValue;
public AbpNavigationEntry(NavigationEntry navigationEntry, string name)
{
NavigationEntry = navigationEntry;
Name = name;
OriginalValue = GetOriginalValue(navigationEntry.CurrentValue);
}
public static List<object>? GetOriginalValue(object? currentValue)
{
if (currentValue is null)
{
return null;
}
if (currentValue is IEnumerable enumerable)
{
return enumerable.Cast<object>().ToList();
}
return new List<object> { currentValue };
}
}

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

@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
@ -193,16 +194,20 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
}
}
if (Options.SaveEntityHistoryWhenNavigationChanges && AbpEfCoreNavigationHelper != null)
if (AbpEfCoreNavigationHelper != null)
{
foreach (var (navigationEntry, index) in entityEntry.Navigations.Select((value, i) => ( value, i )))
{
if (AbpEfCoreNavigationHelper.IsNavigationEntryModified(entityEntry, index))
{
var abpNavigationEntry = AbpEfCoreNavigationHelper.GetNavigationEntry(entityEntry, index);
var isCollection = navigationEntry.Metadata.IsCollection;
propertyChanges.Add(new EntityPropertyChangeInfo
{
PropertyName = navigationEntry.Metadata.Name,
PropertyTypeFullName = navigationEntry.Metadata.ClrType.GetFirstGenericArgumentIfNullable().FullName!
PropertyTypeFullName = navigationEntry.Metadata.ClrType.GetFirstGenericArgumentIfNullable().FullName!,
OriginalValue = GetNavigationPropertyValue(abpNavigationEntry?.OriginalValue, isCollection),
NewValue = GetNavigationPropertyValue(abpNavigationEntry?.CurrentValue, isCollection)
});
}
}
@ -211,6 +216,44 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
return propertyChanges;
}
protected virtual string? GetNavigationPropertyValue(object? entity, bool isCollection)
{
switch (entity)
{
case null:
return null;
case IEntity entryEntity:
var keys = entryEntity.GetKeys();
return keys.Length == 0 ? null : string.Join(", ",keys).TruncateWithPostfix(EntityPropertyChangeInfo.MaxValueLength);
case IEnumerable enumerable:
var keysList = new List<string>();
foreach (var item in enumerable)
{
var id = GetNavigationPropertyValue(item, false);
if (id != null)
{
keysList.Add(id);
}
}
if (keysList.Count == 0)
{
return null;
}
var serializedKeysEnumerable = keysList.Count == 1 && !isCollection
? keysList.First()
: JsonSerializer.Serialize(keysList);
return serializedKeysEnumerable.TruncateWithPostfix(EntityPropertyChangeInfo.MaxValueLength);
default:
return null;
}
}
protected virtual bool IsCreated(EntityEntry entityEntry)
{
return entityEntry.State == EntityState.Added;

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

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
@ -512,7 +513,9 @@ public class Auditing_Tests : AbpAuditingTestBase
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));
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(AppEntityWithNavigationChildOneToOne).FullName &&
x.EntityChanges[1].PropertyChanges[0].OriginalValue == null &&
x.EntityChanges[1].PropertyChanges[0].NewValue == entityId.ToString()));
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
@ -539,10 +542,13 @@ public class Auditing_Tests : AbpAuditingTestBase
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));
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(AppEntityWithNavigationChildOneToOne).FullName &&
x.EntityChanges[1].PropertyChanges[0].OriginalValue == entityId.ToString() &&
x.EntityChanges[1].PropertyChanges[0].NewValue == null));
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
var oneToManyId = "";
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())
@ -561,6 +567,8 @@ public class Auditing_Tests : AbpAuditingTestBase
await repository.UpdateAsync(entity);
await uow.CompleteAsync();
await scope.SaveAsync();
oneToManyId = entity.OneToMany.First().Id.ToString();
}
}
@ -572,36 +580,80 @@ public class Auditing_Tests : AbpAuditingTestBase
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));
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildOneToMany>).FullName &&
x.EntityChanges[1].PropertyChanges[0].OriginalValue == null &&
x.EntityChanges[1].PropertyChanges[0].NewValue == $"[\"{oneToManyId}\"]"));
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
var newOneToManyId = "";
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())
{
var entity = await repository.GetAsync(entityId);
entity.OneToMany = null;
entity.OneToMany.Add(new AppEntityWithNavigationChildOneToMany
{
AppEntityWithNavigationId = entity.Id,
ChildName = "ChildName2"
});
await repository.UpdateAsync(entity);
await uow.CompleteAsync();
await scope.SaveAsync();
newOneToManyId = JsonSerializer.Serialize(entity.OneToMany.Select(x => x.Id).ToList());
}
}
#pragma warning disable 4014
AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 2 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Deleted &&
x.EntityChanges[0].ChangeType == EntityChangeType.Created &&
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));
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildOneToMany>).FullName &&
x.EntityChanges[1].PropertyChanges[0].OriginalValue == $"[\"{oneToManyId}\"]" &&
x.EntityChanges[1].PropertyChanges[0].NewValue == newOneToManyId));
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())
{
var entity = await repository.GetAsync(entityId);
newOneToManyId = JsonSerializer.Serialize(entity.OneToMany.Select(x => x.Id).ToList());
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 == 3 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Deleted &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithNavigationChildOneToMany).FullName &&
x.EntityChanges[1].ChangeType == EntityChangeType.Deleted &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigationChildOneToMany).FullName &&
x.EntityChanges[2].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[2].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName &&
x.EntityChanges[2].PropertyChanges.Count == 1 &&
x.EntityChanges[2].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.OneToMany) &&
x.EntityChanges[2].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildOneToMany>).FullName &&
x.EntityChanges[2].PropertyChanges[0].OriginalValue == newOneToManyId &&
x.EntityChanges[2].PropertyChanges[0].NewValue == null));
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
var manyToManyId = "";
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())
@ -619,6 +671,8 @@ public class Auditing_Tests : AbpAuditingTestBase
await repository.UpdateAsync(entity);
await uow.CompleteAsync();
await scope.SaveAsync();
manyToManyId = entity.ManyToMany.First().Id.ToString();
}
}
@ -630,7 +684,9 @@ public class Auditing_Tests : AbpAuditingTestBase
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName &&
x.EntityChanges[1].PropertyChanges.Count == 1 &&
x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.ManyToMany) &&
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildManyToMany>).FullName));
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildManyToMany>).FullName &&
x.EntityChanges[1].PropertyChanges[0].OriginalValue == null &&
x.EntityChanges[1].PropertyChanges[0].NewValue == $"[\"{manyToManyId}\"]"));
#pragma warning restore 4014
@ -655,6 +711,8 @@ public class Auditing_Tests : AbpAuditingTestBase
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[0].PropertyChanges[0].OriginalValue == $"[\"{manyToManyId}\"]" &&
x.EntityChanges[0].PropertyChanges[0].NewValue == null &&
x.EntityChanges[1].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigationChildManyToMany).FullName &&

2
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/en.json

@ -48,7 +48,7 @@
"ChangeType": "Change type",
"ChangeTime": "Time",
"NewValue": "New value",
"OriginalValue": "Original value",
"OriginalValue": "Old value",
"PropertyName": "Property name",
"PropertyTypeFullName": "Property Type Full Name",
"Yes": "Yes",

39
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogEntityTypeFullNameConverter.cs

@ -0,0 +1,39 @@
using System;
using System.Text.RegularExpressions;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AuditLogging;
public class AuditLogEntityTypeFullNameConverter : ITransientDependency
{
public virtual string Convert(string typeFullName)
{
var genericType = Regex.Match(typeFullName, @"(.+?)`1\[\[");
if (!genericType.Success)
{
return ReplaceGenericSymbol(typeFullName);
}
var type = Regex.Match(typeFullName, @"`1\[\[(.+?), ");
if (!type.Success)
{
return typeFullName;
}
if (type.Groups[1].Value.Contains("System.Nullable`1[["))
{
return genericType.Groups[1].Value + "<" + type.Groups[1].Value.Replace("System.Nullable`1[[", "") + "?>";
}
return genericType.Groups[1].Value.Contains("System.Nullable")
? type.Groups[1].Value + "?"
: genericType.Groups[1].Value + "<" + ReplaceGenericSymbol(type.Groups[1].Value) + ">";
}
protected virtual string ReplaceGenericSymbol(string typeFullName)
{
return typeFullName.Contains("`1+")
? typeFullName.Substring(0, typeFullName.IndexOf("[[", StringComparison.Ordinal)).Replace("`1+", ".")
: typeFullName;
}
}

18
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogInfoToAuditLogConverter.cs

@ -19,12 +19,19 @@ public class AuditLogInfoToAuditLogConverter : IAuditLogInfoToAuditLogConverter,
protected IExceptionToErrorInfoConverter ExceptionToErrorInfoConverter { get; }
protected IJsonSerializer JsonSerializer { get; }
protected AbpExceptionHandlingOptions ExceptionHandlingOptions { get; }
protected AuditLogEntityTypeFullNameConverter AuditLogEntityTypeFullNameConverter { get; }
public AuditLogInfoToAuditLogConverter(IGuidGenerator guidGenerator, IExceptionToErrorInfoConverter exceptionToErrorInfoConverter, IJsonSerializer jsonSerializer, IOptions<AbpExceptionHandlingOptions> exceptionHandlingOptions)
public AuditLogInfoToAuditLogConverter(
IGuidGenerator guidGenerator,
IExceptionToErrorInfoConverter exceptionToErrorInfoConverter,
IJsonSerializer jsonSerializer,
IOptions<AbpExceptionHandlingOptions> exceptionHandlingOptions,
AuditLogEntityTypeFullNameConverter auditLogEntityTypeFullNameConverter)
{
GuidGenerator = guidGenerator;
ExceptionToErrorInfoConverter = exceptionToErrorInfoConverter;
JsonSerializer = jsonSerializer;
AuditLogEntityTypeFullNameConverter = auditLogEntityTypeFullNameConverter;
ExceptionHandlingOptions = exceptionHandlingOptions.Value;
}
@ -41,6 +48,15 @@ public class AuditLogInfoToAuditLogConverter : IAuditLogInfoToAuditLogConverter,
}
}
foreach (var entityChange in auditLogInfo.EntityChanges ?? Enumerable.Empty<EntityChangeInfo>())
{
entityChange.EntityTypeFullName = AuditLogEntityTypeFullNameConverter.Convert(entityChange.EntityTypeFullName);
foreach (var propertyChange in entityChange.PropertyChanges ?? Enumerable.Empty<EntityPropertyChangeInfo>())
{
propertyChange.PropertyTypeFullName = AuditLogEntityTypeFullNameConverter.Convert(propertyChange.PropertyTypeFullName);
}
}
var entityChanges = auditLogInfo
.EntityChanges?
.Select(entityChangeInfo => new EntityChange(GuidGenerator, auditLogId, entityChangeInfo, tenantId: auditLogInfo.TenantId))

6
modules/audit-logging/test/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests/Volo/Abp/AuditLogging/EntityFrameworkCore/AuditLogEntityTypeFullNameConverter_Tests.cs

@ -0,0 +1,6 @@
namespace Volo.Abp.AuditLogging.EntityFrameworkCore;
public class AuditLogEntityTypeFullNameConverter_Tests : AuditLogEntityTypeFullNameConverter_Tests<AbpAuditLoggingEntityFrameworkCoreTestModule>
{
}

9
modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo/Abp/AuditLogging/MongoDB/AuditLogEntityTypeFullNameConverter_Tests.cs

@ -0,0 +1,9 @@
using Xunit;
namespace Volo.Abp.AuditLogging.MongoDB;
[Collection(MongoTestCollection.Name)]
public class AuditLogEntityTypeFullNameConverter_Tests : AuditLogEntityTypeFullNameConverter_Tests<AbpAuditLoggingMongoDbTestModule>
{
}

46
modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditLogEntityTypeFullNameConverter_Tests.cs

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Shouldly;
using Volo.Abp.Modularity;
using Xunit;
namespace Volo.Abp.AuditLogging;
public abstract class AuditLogEntityTypeFullNameConverter_Tests<TStartupModule> : AuditLoggingTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly AuditLogEntityTypeFullNameConverter _typeFullNameConverter;
protected AuditLogEntityTypeFullNameConverter_Tests()
{
_typeFullNameConverter = GetRequiredService<AuditLogEntityTypeFullNameConverter>();
}
[Fact]
public void AuditLogEntityTypeFullNameConverter_Test()
{
_typeFullNameConverter.Convert("MyType").ShouldBe("MyType");
_typeFullNameConverter.Convert(typeof(string).FullName!).ShouldBe("System.String");
_typeFullNameConverter.Convert(typeof(Guid).FullName!).ShouldBe("System.Guid");
_typeFullNameConverter.Convert(typeof(Guid?).FullName!).ShouldBe("System.Guid?");
_typeFullNameConverter.Convert(typeof(int).FullName!).ShouldBe("System.Int32");
_typeFullNameConverter.Convert(typeof(long?).FullName!).ShouldBe("System.Int64?");
_typeFullNameConverter.Convert(typeof(MyClass).FullName!).ShouldBe("Volo.Abp.AuditLogging.AuditLogEntityTypeFullNameConverter_Tests.MyClass");
_typeFullNameConverter.Convert(typeof(ICollection<string>).FullName!).ShouldBe($"System.Collections.Generic.ICollection<System.String>");
_typeFullNameConverter.Convert(typeof(Collection<int>).FullName!).ShouldBe($"System.Collections.ObjectModel.Collection<System.Int32>");
_typeFullNameConverter.Convert(typeof(List<Guid>).FullName!).ShouldBe($"System.Collections.Generic.List<System.Guid>");
_typeFullNameConverter.Convert(typeof(List<MyClass>).FullName!).ShouldBe($"System.Collections.Generic.List<Volo.Abp.AuditLogging.AuditLogEntityTypeFullNameConverter_Tests.MyClass>");
_typeFullNameConverter.Convert(typeof(ICollection<long?>).FullName!).ShouldBe($"System.Collections.Generic.ICollection<System.Int64?>");
_typeFullNameConverter.Convert(typeof(Collection<int?>).FullName!).ShouldBe($"System.Collections.ObjectModel.Collection<System.Int32?>");
_typeFullNameConverter.Convert(typeof(List<Guid?>).FullName!).ShouldBe($"System.Collections.Generic.List<System.Guid?>");
}
public class MyClass
{
}
}
Loading…
Cancel
Save