Browse Source

Merge pull request #19539 from abpframework/auto-merge/rel-8-0/2632

Merge branch rel-8.1 with rel-8.0
pull/19540/head
maliming 2 years ago
committed by GitHub
parent
commit
cde5debf94
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 15
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs
  2. 132
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEfCoreNavigationHelper.cs
  3. 10
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEntityEntryNavigationProperty.cs
  4. 5
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs

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

@ -181,6 +181,7 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
if (entityChangeList != null) if (entityChangeList != null)
{ {
EntityHistoryHelper.UpdateChangeList(entityChangeList); EntityHistoryHelper.UpdateChangeList(entityChangeList);
AbpEfCoreNavigationHelper.Clear();
auditLog!.EntityChanges.AddRange(entityChangeList); auditLog!.EntityChanges.AddRange(entityChangeList);
Logger.LogDebug($"Added {entityChangeList.Count} entity changes to the current audit log"); Logger.LogDebug($"Added {entityChangeList.Count} entity changes to the current audit log");
} }
@ -343,6 +344,18 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
EntityChangeEventHelper.PublishEntityUpdatedEvent(entry.Entity); EntityChangeEventHelper.PublishEntityUpdatedEvent(entry.Entity);
} }
} }
else if (EntityChangeOptions.Value.PublishEntityUpdatedEventWhenNavigationChanges &&
(entry.Navigations.Any(x => x.IsModified) || AbpEfCoreNavigationHelper.IsEntityEntryNavigationChanged(entry)))
{
if (entry.Entity is ISoftDelete && entry.Entity.As<ISoftDelete>().IsDeleted)
{
EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity);
}
else
{
EntityChangeEventHelper.PublishEntityUpdatedEvent(entry.Entity);
}
}
break; break;
case EntityState.Deleted: case EntityState.Deleted:
@ -353,7 +366,7 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
if (EntityChangeOptions.Value.PublishEntityUpdatedEventWhenNavigationChanges) if (EntityChangeOptions.Value.PublishEntityUpdatedEventWhenNavigationChanges)
{ {
foreach (var entityEntry in ChangeTracker.Entries().Where(x => x.State == EntityState.Unchanged && AbpEfCoreNavigationHelper.IsEntityEntryNavigationChanged(x))) foreach (var entityEntry in AbpEfCoreNavigationHelper.GetChangedEntityEntries())
{ {
if (entityEntry.Entity is ISoftDelete && entityEntry.Entity.As<ISoftDelete>().IsDeleted) if (entityEntry.Entity is ISoftDelete && entityEntry.Entity.As<ISoftDelete>().IsDeleted)
{ {

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

@ -15,25 +15,21 @@ namespace Volo.Abp.EntityFrameworkCore.ChangeTrackers;
/// </summary> /// </summary>
public class AbpEfCoreNavigationHelper : ITransientDependency public class AbpEfCoreNavigationHelper : ITransientDependency
{ {
private Dictionary<string, List<AbpEntityEntryNavigationProperty>> EntityEntryNavigationProperties { get; } = new (); protected Dictionary<string, List<AbpEntityEntryNavigationProperty>> EntityEntryNavigationProperties { get; } = new Dictionary<string, List<AbpEntityEntryNavigationProperty>>();
public virtual void ChangeTracker_Tracked(ChangeTracker changeTracker, object? sender, EntityTrackedEventArgs e) public virtual void ChangeTracker_Tracked(ChangeTracker changeTracker, object? sender, EntityTrackedEventArgs e)
{ {
foreach (var entry in changeTracker.Entries()) EntityEntryTrackedOrStateChanged(e.Entry);
{ DetectChanges();
EntityEntryTrackedOrStateChanged(entry);
}
} }
public virtual void ChangeTracker_StateChanged(ChangeTracker changeTracker, object? sender, EntityStateChangedEventArgs e) public virtual void ChangeTracker_StateChanged(ChangeTracker changeTracker, object? sender, EntityStateChangedEventArgs e)
{ {
foreach (var entry in changeTracker.Entries()) EntityEntryTrackedOrStateChanged(e.Entry);
{ DetectChanges();
EntityEntryTrackedOrStateChanged(entry);
}
} }
private void EntityEntryTrackedOrStateChanged(EntityEntry entityEntry) protected virtual void EntityEntryTrackedOrStateChanged(EntityEntry entityEntry)
{ {
if (entityEntry.State != EntityState.Unchanged) if (entityEntry.State != EntityState.Unchanged)
{ {
@ -50,44 +46,79 @@ public class AbpEfCoreNavigationHelper : ITransientDependency
var index = 0; var index = 0;
foreach (var navigationEntry in entityEntry.Navigations.Where(navigation => !navigation.IsModified)) foreach (var navigationEntry in entityEntry.Navigations.Where(navigation => !navigation.IsModified))
{ {
if (!navigationEntry.IsLoaded && navigationEntry.CurrentValue == null) var navigationProperty = navigationProperties.FirstOrDefault(x => x.Index == index);
if (navigationProperty != null)
{ {
index++; if (navigationProperty.Value == null || IsCollectionAndEmpty(navigationProperty.Value))
continue; {
navigationProperty.Value = navigationEntry.CurrentValue;
}
} }
else
var currentValue = navigationEntry.CurrentValue;
if (navigationEntry.CurrentValue is ICollection collection)
{ {
currentValue = collection.Cast<object?>().ToList(); navigationProperties.Add(new AbpEntityEntryNavigationProperty(index, navigationEntry.Metadata.Name, navigationEntry.CurrentValue, false, entityEntry, navigationEntry));
} }
var navigationProperty = navigationProperties.FirstOrDefault(x => x.Index == index); index++;
if (navigationProperty != null) }
}
protected virtual void DetectChanges()
{
foreach (var entityEntryNavigationProperties in EntityEntryNavigationProperties)
{
foreach (var navigationProperty in entityEntryNavigationProperties.Value.Where(x => !x.IsChanged && x.EntityEntry.State == EntityState.Unchanged))
{ {
if (!navigationProperty.IsChanged && (navigationProperty.Value == null || IsCollectionAndEmpty(navigationProperty.Value))) if (navigationProperty.NavigationEntry.IsModified)
{ {
navigationProperty.Value = currentValue; navigationProperty.IsChanged = true;
navigationProperty.IsChanged = currentValue != null && !IsCollectionAndEmpty(currentValue); continue;
} }
if (!navigationProperty.IsChanged && navigationProperty.Value != null && !IsCollectionAndEmpty(navigationProperty.Value)) if (navigationProperty.Value == null || IsCollectionAndEmpty(navigationProperty.Value))
{ {
navigationProperty.Value = currentValue; if (navigationProperty.NavigationEntry.CurrentValue != null || IsCollectionAndNotEmpty(navigationProperty.NavigationEntry.CurrentValue))
navigationProperty.IsChanged = currentValue == null || IsCollectionAndEmpty(currentValue); {
if (navigationProperty.NavigationEntry.CurrentValue is ICollection collection)
{
navigationProperty.Value = collection.Cast<object?>().ToList();
}
else
{
navigationProperty.Value = navigationProperty.NavigationEntry.CurrentValue;
}
}
} }
}
else
{
navigationProperties.Add(new AbpEntityEntryNavigationProperty(index, navigationEntry.Metadata.Name, currentValue, false));
}
index++; if (navigationProperty.Value != null || IsCollectionAndNotEmpty(navigationProperty.Value))
{
if (navigationProperty.NavigationEntry.CurrentValue == null || IsCollectionAndEmpty(navigationProperty.NavigationEntry.CurrentValue))
{
if (IsCollectionAndEmpty(navigationProperty.Value) && IsCollectionAndEmpty(navigationProperty.NavigationEntry.CurrentValue))
{
continue;
}
navigationProperty.IsChanged = true;
}
}
}
} }
} }
public bool IsEntityEntryNavigationChanged(EntityEntry entityEntry) public virtual List<EntityEntry> GetChangedEntityEntries()
{
DetectChanges();
return EntityEntryNavigationProperties
.SelectMany(x => x.Value)
.Where(x => x.NavigationEntry.IsModified || x.IsChanged)
.Select(x => x.EntityEntry)
.ToList();
}
public virtual bool IsEntityEntryNavigationChanged(EntityEntry entityEntry)
{ {
DetectChanges();
if (entityEntry.State == EntityState.Modified) if (entityEntry.State == EntityState.Modified)
{ {
return true; return true;
@ -99,32 +130,19 @@ public class AbpEfCoreNavigationHelper : ITransientDependency
return false; return false;
} }
var index = 0; if (EntityEntryNavigationProperties.TryGetValue(entryId, out var navigationProperties))
foreach (var navigationEntry in entityEntry.Navigations)
{ {
if (navigationEntry.IsModified || (navigationEntry is ReferenceEntry && navigationEntry.As<ReferenceEntry>().TargetEntry?.State == EntityState.Modified)) return navigationProperties.Any(x => x.IsChanged) ||
{ navigationProperties.Any(x => x.NavigationEntry.IsModified) ||
return true; navigationProperties.Any(x =>
} x.NavigationEntry is ReferenceEntry &&
x.NavigationEntry.As<ReferenceEntry>().TargetEntry?.State == EntityState.Modified);
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; return false;
} }
public bool IsEntityEntryNavigationChanged(NavigationEntry navigationEntry, int index) public virtual bool IsEntityEntryNavigationChanged(NavigationEntry navigationEntry, int index)
{ {
if (navigationEntry.IsModified || (navigationEntry is ReferenceEntry && navigationEntry.As<ReferenceEntry>().TargetEntry?.State == EntityState.Modified)) if (navigationEntry.IsModified || (navigationEntry is ReferenceEntry && navigationEntry.As<ReferenceEntry>().TargetEntry?.State == EntityState.Modified))
{ {
@ -149,6 +167,11 @@ public class AbpEfCoreNavigationHelper : ITransientDependency
return false; return false;
} }
public void Clear()
{
EntityEntryNavigationProperties.Clear();
}
private string? GetEntityId(EntityEntry entityEntry) private string? GetEntityId(EntityEntry entityEntry)
{ {
return entityEntry.Entity is IEntity entryEntity && entryEntity.GetKeys().Length == 1 return entityEntry.Entity is IEntity entryEntity && entryEntity.GetKeys().Length == 1
@ -160,4 +183,9 @@ public class AbpEfCoreNavigationHelper : ITransientDependency
{ {
return value is ICollection && value is ICollection collection && collection.Count == 0; return value is ICollection && value is ICollection collection && collection.Count == 0;
} }
private bool IsCollectionAndNotEmpty(object? value)
{
return value is ICollection && value is ICollection collection && collection.Count != 0;
}
} }

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

@ -1,3 +1,5 @@
using Microsoft.EntityFrameworkCore.ChangeTracking;
namespace Volo.Abp.EntityFrameworkCore.ChangeTrackers; namespace Volo.Abp.EntityFrameworkCore.ChangeTrackers;
public class AbpEntityEntryNavigationProperty public class AbpEntityEntryNavigationProperty
@ -10,11 +12,17 @@ public class AbpEntityEntryNavigationProperty
public bool IsChanged { get; set; } public bool IsChanged { get; set; }
public AbpEntityEntryNavigationProperty(int index, string name, object? value, bool isChanged) public EntityEntry EntityEntry { get; set; }
public NavigationEntry NavigationEntry { get; set; }
public AbpEntityEntryNavigationProperty(int index, string name, object? value, bool isChanged, EntityEntry entityEntry, NavigationEntry navigationEntry)
{ {
Index = index; Index = index;
Name = name; Name = name;
Value = value; Value = value;
IsChanged = isChanged; IsChanged = isChanged;
EntityEntry = entityEntry;
NavigationEntry = navigationEntry;
} }
} }

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

@ -255,7 +255,10 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
protected virtual bool HasNavigationPropertiesChanged(EntityEntry entityEntry) protected virtual bool HasNavigationPropertiesChanged(EntityEntry entityEntry)
{ {
return entityEntry.State == EntityState.Unchanged && Options.SaveEntityHistoryWhenNavigationChanges && AbpEfCoreNavigationHelper != null && AbpEfCoreNavigationHelper.IsEntityEntryNavigationChanged(entityEntry); return entityEntry.State == EntityState.Unchanged &&
Options.SaveEntityHistoryWhenNavigationChanges &&
AbpEfCoreNavigationHelper != null &&
AbpEfCoreNavigationHelper.IsEntityEntryNavigationChanged(entityEntry);
} }
protected virtual bool ShouldSavePropertyHistory(PropertyEntry propertyEntry, bool defaultValue) protected virtual bool ShouldSavePropertyHistory(PropertyEntry propertyEntry, bool defaultValue)

Loading…
Cancel
Save