Browse Source

Improve entity history handling for shared types and JSON

Enhanced EntityHistoryHelper to correctly handle entities with shared CLR types and properties mapped to JSON. Added logic to determine property type from entry values when the type is object, and improved property change tracking for JSON-mapped navigation properties.
pull/24519/head
SALİH ÖZKARA 9 months ago
parent
commit
f253f9945e
  1. 55
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs

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

@ -5,6 +5,7 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -108,12 +109,17 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
} }
var entityType = entity.GetType(); var entityType = entity.GetType();
var entityFullName = entityType.FullName!;
if (entityEntry.Metadata.HasSharedClrType)
{
entityFullName = entityEntry.Metadata.Name;
}
var entityChange = new EntityChangeInfo var entityChange = new EntityChangeInfo
{ {
ChangeType = changeType, ChangeType = changeType,
EntityEntry = entityEntry, EntityEntry = entityEntry,
EntityId = entityId, EntityId = entityId,
EntityTypeFullName = entityType.FullName, EntityTypeFullName = entityFullName,
PropertyChanges = GetPropertyChanges(entityEntry), PropertyChanges = GetPropertyChanges(entityEntry),
EntityTenantId = GetTenantId(entity) EntityTenantId = GetTenantId(entity)
}; };
@ -184,12 +190,14 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
var propertyEntry = entityEntry.Property(property.Name); var propertyEntry = entityEntry.Property(property.Name);
if (ShouldSavePropertyHistory(propertyEntry, isCreated || isDeleted) && !IsSoftDeleted(entityEntry)) if (ShouldSavePropertyHistory(propertyEntry, isCreated || isDeleted) && !IsSoftDeleted(entityEntry))
{ {
var propertyType = DeterminePropertyTypeFromEntry(property, propertyEntry);
propertyChanges.Add(new EntityPropertyChangeInfo propertyChanges.Add(new EntityPropertyChangeInfo
{ {
NewValue = isDeleted ? null : JsonSerializer.Serialize(propertyEntry.CurrentValue!).TruncateWithPostfix(EntityPropertyChangeInfo.MaxValueLength), NewValue = isDeleted ? null : JsonSerializer.Serialize(propertyEntry.CurrentValue!).TruncateWithPostfix(EntityPropertyChangeInfo.MaxValueLength),
OriginalValue = isCreated ? null : JsonSerializer.Serialize(propertyEntry.OriginalValue!).TruncateWithPostfix(EntityPropertyChangeInfo.MaxValueLength), OriginalValue = isCreated ? null : JsonSerializer.Serialize(propertyEntry.OriginalValue!).TruncateWithPostfix(EntityPropertyChangeInfo.MaxValueLength),
PropertyName = property.Name, PropertyName = property.Name,
PropertyTypeFullName = property.ClrType.GetFirstGenericArgumentIfNullable().FullName! PropertyTypeFullName = propertyType.FullName!
}); });
} }
} }
@ -208,14 +216,22 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
if (AbpEfCoreNavigationHelper.IsNavigationEntryModified(entityEntry, index)) if (AbpEfCoreNavigationHelper.IsNavigationEntryModified(entityEntry, index))
{ {
var abpNavigationEntry = AbpEfCoreNavigationHelper.GetNavigationEntry(entityEntry, index); var abpNavigationEntry = AbpEfCoreNavigationHelper.GetNavigationEntry(entityEntry, index);
var isCollection = navigationEntry.Metadata.IsCollection; if (navigationEntry.Metadata.TargetEntityType.IsMappedToJson() && navigationEntry is ReferenceEntry referenceEntry && referenceEntry.TargetEntry != null)
propertyChanges.Add(new EntityPropertyChangeInfo {
var jsonPropertyChanges = GetPropertyChanges(referenceEntry.TargetEntry);
propertyChanges.AddRange(jsonPropertyChanges);
}
else
{ {
PropertyName = navigationEntry.Metadata.Name, var isCollection = navigationEntry.Metadata.IsCollection;
PropertyTypeFullName = navigationEntry.Metadata.ClrType.GetFirstGenericArgumentIfNullable().FullName!, propertyChanges.Add(new EntityPropertyChangeInfo
OriginalValue = GetNavigationPropertyValue(abpNavigationEntry?.OriginalValue, isCollection), {
NewValue = GetNavigationPropertyValue(abpNavigationEntry?.CurrentValue, isCollection) PropertyName = navigationEntry.Metadata.Name,
}); PropertyTypeFullName = navigationEntry.Metadata.ClrType.GetFirstGenericArgumentIfNullable().FullName!,
OriginalValue = GetNavigationPropertyValue(abpNavigationEntry?.OriginalValue, isCollection),
NewValue = GetNavigationPropertyValue(abpNavigationEntry?.CurrentValue, isCollection)
});
}
} }
} }
} }
@ -223,6 +239,27 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
return propertyChanges; return propertyChanges;
} }
protected virtual Type DeterminePropertyTypeFromEntry(IProperty property, PropertyEntry propertyEntry)
{
var propertyType = property.ClrType.GetFirstGenericArgumentIfNullable();
if (propertyType != typeof(object))
{
return propertyType;
}
if (propertyEntry.CurrentValue != null)
{
propertyType = propertyEntry.CurrentValue.GetType().GetFirstGenericArgumentIfNullable();
}
else if (propertyEntry.OriginalValue != null)
{
propertyType = propertyEntry.OriginalValue.GetType().GetFirstGenericArgumentIfNullable();
}
return propertyType;
}
protected virtual string? GetNavigationPropertyValue(object? entity, bool isCollection) protected virtual string? GetNavigationPropertyValue(object? entity, bool isCollection)
{ {
switch (entity) switch (entity)

Loading…
Cancel
Save