From d51c565a1fa1e2257c72b0dd74da39e3f73d1ceb Mon Sep 17 00:00:00 2001 From: maliming Date: Sat, 19 Jul 2025 16:00:49 +0800 Subject: [PATCH] Refactor `UpdateNavigationEntries` method to improve performance. --- .../AbpEfCoreNavigationHelper.cs | 14 ++++- .../ChangeTrackers/AbpEntityEntry.cs | 59 +++++++------------ 2 files changed, 32 insertions(+), 41 deletions(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEfCoreNavigationHelper.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEfCoreNavigationHelper.cs index 3d7b12f86e..1338e68400 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEfCoreNavigationHelper.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEfCoreNavigationHelper.cs @@ -60,7 +60,7 @@ public class AbpEfCoreNavigationHelper : ITransientDependency return; } - var foreignKeys = entityEntry.Metadata.GetForeignKeys().ToList(); + var foreignKeys = entityEntry.Metadata.GetForeignKeys(); foreach (var foreignKey in foreignKeys) { var principal = stateManager.FindPrincipal(internalEntityEntityEntry, foreignKey); @@ -75,7 +75,11 @@ public class AbpEfCoreNavigationHelper : ITransientDependency continue; } - abpEntityEntry.UpdateNavigationEntries(); + if (checkEntityEntryState && entityEntry.State == EntityState.Unchanged) + { + abpEntityEntry.UpdateNavigationEntries(entityEntry, foreignKey); + } + if (!abpEntityEntry.IsModified && (!checkEntityEntryState || IsEntityEntryChanged(entityEntry))) { abpEntityEntry.IsModified = true; @@ -115,7 +119,11 @@ public class AbpEfCoreNavigationHelper : ITransientDependency continue; } - abpEntityEntry.UpdateNavigationEntries(); + if (checkEntityEntryState && entityEntry.State == EntityState.Unchanged) + { + abpEntityEntry.UpdateNavigationEntries(entityEntry, inverseForeignKey); + } + if (!abpEntityEntry.IsModified && (!checkEntityEntryState || IsEntityEntryChanged(entityEntry))) { abpEntityEntry.IsModified = true; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEntityEntry.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEntityEntry.cs index 8d597f85b5..00b38b289e 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEntityEntry.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEntityEntry.cs @@ -1,8 +1,9 @@ -using System.Collections; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.Metadata; namespace Volo.Abp.EntityFrameworkCore.ChangeTrackers; @@ -31,42 +32,34 @@ public class AbpEntityEntry NavigationEntries = EntityEntry.Navigations.Select(x => new AbpNavigationEntry(x, x.Metadata.Name)).ToList(); } - public void UpdateNavigationEntries() + public void UpdateNavigationEntries(EntityEntry entityEntry, IForeignKey foreignKey) { + var entityEntryNavigationEntry = NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is INavigation navigationMetadata && navigationMetadata.ForeignKey == foreignKey) ?? + NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is ISkipNavigation skipNavigationMetadata && skipNavigationMetadata.ForeignKey == foreignKey); foreach (var navigationEntry in NavigationEntries) { if (IsModified || EntityEntry.State == EntityState.Modified || - navigationEntry.IsModified || - navigationEntry.NavigationEntry.IsModified) + navigationEntry.IsModified) { continue; } - var currentValue = AbpNavigationEntry.GetOriginalValue(navigationEntry.NavigationEntry.CurrentValue); + var currentValue = navigationEntry.NavigationEntry.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().ToList(); - var newList = currentValueCollection.Cast().ToList(); - if (newList.Count > existingList.Count) - { - navigationEntry.OriginalValue = currentValue; - } - break; - } - default: - navigationEntry.OriginalValue = currentValue; - break; + if (navigationEntry.NavigationEntry is CollectionEntry && navigationEntry == entityEntryNavigationEntry) + { + navigationEntry.OriginalValue ??= new List(); + var ls = navigationEntry.OriginalValue.As>(); + ls.Add(entityEntry.Entity); + } + else + { + navigationEntry.OriginalValue = currentValue; } } } @@ -80,7 +73,7 @@ public class AbpNavigationEntry public bool IsModified { get; set; } - public List? OriginalValue { get; set; } + public object? OriginalValue { get; set; } public object? CurrentValue => NavigationEntry.CurrentValue; @@ -88,21 +81,11 @@ public class AbpNavigationEntry { NavigationEntry = navigationEntry; Name = name; - OriginalValue = GetOriginalValue(navigationEntry.CurrentValue); - } - - public static List? GetOriginalValue(object? currentValue) - { - if (currentValue is null) + if (navigationEntry.CurrentValue != null) { - return null; + OriginalValue = navigationEntry is CollectionEntry collection + ? collection.CurrentValue!.Cast().ToList() + : navigationEntry.CurrentValue; } - - if (currentValue is IEnumerable enumerable) - { - return enumerable.Cast().ToList(); - } - - return new List { currentValue }; } }