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)
{
EntityHistoryHelper.UpdateChangeList(entityChangeList);
AbpEfCoreNavigationHelper.Clear();
auditLog!.EntityChanges.AddRange(entityChangeList);
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);
}
}
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;
case EntityState.Deleted:
@ -353,7 +366,7 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
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)
{

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

@ -15,25 +15,21 @@ namespace Volo.Abp.EntityFrameworkCore.ChangeTrackers;
/// </summary>
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)
{
foreach (var entry in changeTracker.Entries())
{
EntityEntryTrackedOrStateChanged(entry);
}
EntityEntryTrackedOrStateChanged(e.Entry);
DetectChanges();
}
public virtual void ChangeTracker_StateChanged(ChangeTracker changeTracker, object? sender, EntityStateChangedEventArgs e)
{
foreach (var entry in changeTracker.Entries())
{
EntityEntryTrackedOrStateChanged(entry);
}
EntityEntryTrackedOrStateChanged(e.Entry);
DetectChanges();
}
private void EntityEntryTrackedOrStateChanged(EntityEntry entityEntry)
protected virtual void EntityEntryTrackedOrStateChanged(EntityEntry entityEntry)
{
if (entityEntry.State != EntityState.Unchanged)
{
@ -50,44 +46,79 @@ public class AbpEfCoreNavigationHelper : ITransientDependency
var index = 0;
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++;
continue;
if (navigationProperty.Value == null || IsCollectionAndEmpty(navigationProperty.Value))
{
navigationProperty.Value = navigationEntry.CurrentValue;
}
}
var currentValue = navigationEntry.CurrentValue;
if (navigationEntry.CurrentValue is ICollection collection)
else
{
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);
if (navigationProperty != null)
index++;
}
}
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 = currentValue != null && !IsCollectionAndEmpty(currentValue);
navigationProperty.IsChanged = true;
continue;
}
if (!navigationProperty.IsChanged && navigationProperty.Value != null && !IsCollectionAndEmpty(navigationProperty.Value))
if (navigationProperty.Value == null || IsCollectionAndEmpty(navigationProperty.Value))
{
navigationProperty.Value = currentValue;
navigationProperty.IsChanged = currentValue == null || IsCollectionAndEmpty(currentValue);
if (navigationProperty.NavigationEntry.CurrentValue != null || IsCollectionAndNotEmpty(navigationProperty.NavigationEntry.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)
{
return true;
@ -99,32 +130,19 @@ public class AbpEfCoreNavigationHelper : ITransientDependency
return false;
}
var index = 0;
foreach (var navigationEntry in entityEntry.Navigations)
if (EntityEntryNavigationProperties.TryGetValue(entryId, out var navigationProperties))
{
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 navigationProperties.Any(x => x.IsChanged) ||
navigationProperties.Any(x => x.NavigationEntry.IsModified) ||
navigationProperties.Any(x =>
x.NavigationEntry is ReferenceEntry &&
x.NavigationEntry.As<ReferenceEntry>().TargetEntry?.State == EntityState.Modified);
}
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))
{
@ -149,6 +167,11 @@ public class AbpEfCoreNavigationHelper : ITransientDependency
return false;
}
public void Clear()
{
EntityEntryNavigationProperties.Clear();
}
private string? GetEntityId(EntityEntry entityEntry)
{
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;
}
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;
public class AbpEntityEntryNavigationProperty
@ -10,11 +12,17 @@ public class AbpEntityEntryNavigationProperty
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;
Name = name;
Value = value;
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)
{
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)

Loading…
Cancel
Save