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..39835569cb 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,15 +75,20 @@ public class AbpEfCoreNavigationHelper : ITransientDependency continue; } - abpEntityEntry.UpdateNavigationEntries(); + var navigationEntry = abpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is INavigation navigationMetadata && navigationMetadata.ForeignKey == foreignKey) ?? + abpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is ISkipNavigation skipNavigationMetadata && skipNavigationMetadata.ForeignKey == foreignKey); + + if (navigationEntry != null && checkEntityEntryState && entityEntry.State == EntityState.Unchanged) + { + abpEntityEntry.UpdateNavigation(entityEntry, navigationEntry); + } + if (!abpEntityEntry.IsModified && (!checkEntityEntryState || IsEntityEntryChanged(entityEntry))) { abpEntityEntry.IsModified = true; DetectChanges(abpEntityEntry.EntityEntry, false); } - var navigationEntry = abpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is INavigation navigationMetadata && navigationMetadata.ForeignKey == foreignKey) ?? - abpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is ISkipNavigation skipNavigationMetadata && skipNavigationMetadata.ForeignKey == foreignKey); if (navigationEntry != null && IsEntityEntryChanged(entityEntry)) { navigationEntry.IsModified = true; @@ -115,15 +120,20 @@ public class AbpEfCoreNavigationHelper : ITransientDependency continue; } - abpEntityEntry.UpdateNavigationEntries(); + var navigationEntry = abpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is INavigation navigationMetadata && navigationMetadata.ForeignKey == inverseForeignKey) ?? + abpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is ISkipNavigation skipNavigationMetadata && skipNavigationMetadata.ForeignKey == inverseForeignKey); + + if (navigationEntry != null && checkEntityEntryState && entityEntry.State == EntityState.Unchanged) + { + abpEntityEntry.UpdateNavigation(entityEntry, navigationEntry); + } + if (!abpEntityEntry.IsModified && (!checkEntityEntryState || IsEntityEntryChanged(entityEntry))) { abpEntityEntry.IsModified = true; DetectChanges(abpEntityEntry.EntityEntry, false); } - var navigationEntry = abpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is INavigation navigationMetadata && navigationMetadata.ForeignKey == inverseForeignKey) ?? - abpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is ISkipNavigation skipNavigationMetadata && skipNavigationMetadata.ForeignKey == inverseForeignKey); if (navigationEntry != null && (!checkEntityEntryState || IsEntityEntryChanged(entityEntry))) { navigationEntry.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..194132d001 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,4 +1,4 @@ -using System.Collections; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore; @@ -31,43 +31,29 @@ public class AbpEntityEntry NavigationEntries = EntityEntry.Navigations.Select(x => new AbpNavigationEntry(x, x.Metadata.Name)).ToList(); } - public void UpdateNavigationEntries() + public void UpdateNavigation(EntityEntry entityEntry, AbpNavigationEntry navigationEntry) { - foreach (var navigationEntry in NavigationEntries) + if (IsModified || + EntityEntry.State == EntityState.Modified || + navigationEntry.IsModified) { - if (IsModified || - EntityEntry.State == EntityState.Modified || - navigationEntry.IsModified || - navigationEntry.NavigationEntry.IsModified) - { - continue; - } + return; + } - var currentValue = AbpNavigationEntry.GetOriginalValue(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; - } + var currentValue = navigationEntry.NavigationEntry.CurrentValue; + if (currentValue == null) + { + return; + } - break; - } - default: - navigationEntry.OriginalValue = currentValue; - break; - } + if (navigationEntry.NavigationEntry is CollectionEntry) + { + navigationEntry.OriginalValue ??= new List(); + navigationEntry.OriginalValue.As>().Add(entityEntry.Entity); + } + else + { + navigationEntry.OriginalValue = currentValue; } } } @@ -80,7 +66,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 +74,9 @@ public class AbpNavigationEntry { NavigationEntry = navigationEntry; Name = name; - OriginalValue = GetOriginalValue(navigationEntry.CurrentValue); - } - - public static List? GetOriginalValue(object? currentValue) - { - if (currentValue is null) - { - return null; - } - - if (currentValue is IEnumerable enumerable) + if (navigationEntry.CurrentValue != null ) { - return enumerable.Cast().ToList(); + OriginalValue = navigationEntry is CollectionEntry ? new List() : navigationEntry.CurrentValue; } - - return new List { currentValue }; } } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEfCoreNavigationHelper_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEfCoreNavigationHelper_Tests.cs index 578bc94417..9d10af9705 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEfCoreNavigationHelper_Tests.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEfCoreNavigationHelper_Tests.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics; using System.Linq; -using System.Threading; using System.Threading.Tasks; using Shouldly; using Volo.Abp.Domain.Repositories; @@ -84,11 +83,8 @@ public class AbpEfCoreNavigationHelper_Tests : EntityFrameworkCoreTestBase stopWatch.Stop(); stopWatch.Elapsed.ShouldBeLessThan(batchUpdateTime); - - var cancellationTokenSource = new CancellationTokenSource(); - cancellationTokenSource.CancelAfter(batchUpdateTime); stopWatch.Restart(); - var blog = await _blogRepository.GetAsync(blogId, cancellationToken: cancellationTokenSource.Token); + var blog = await _blogRepository.GetAsync(blogId); blog.BlogPosts.Count.ShouldBe(5 * 1000 + 1); stopWatch.Stop(); stopWatch.Elapsed.ShouldBeLessThan(queryTime);