From b190edcccbc5ec9b855f686fd9fea894b7ca3634 Mon Sep 17 00:00:00 2001 From: Vasily Chefonov <81791194+vasiliy-chefonov@users.noreply.github.com> Date: Fri, 7 Feb 2025 20:57:37 +0700 Subject: [PATCH] Fix the issue with navigation collections SN-776 --- .../NavigationCollectionField.razor.cs | 13 +++++++-- .../EfCore/Services/EfCoreDataService.cs | 27 ++++++------------- .../EfCore/Services/ProxyToPocoConverter.cs | 6 ++--- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/Saritasa.NetForge/Controls/CustomFields/NavigationCollectionField.razor.cs b/src/Saritasa.NetForge/Controls/CustomFields/NavigationCollectionField.razor.cs index e67d822c..17f89519 100644 --- a/src/Saritasa.NetForge/Controls/CustomFields/NavigationCollectionField.razor.cs +++ b/src/Saritasa.NetForge/Controls/CustomFields/NavigationCollectionField.razor.cs @@ -1,6 +1,9 @@ using Microsoft.AspNetCore.Components; using Saritasa.NetForge.Domain.UseCases.Interfaces; using Saritasa.NetForge.Domain.UseCases.Metadata.GetEntityById; +using Saritasa.NetForge.Infrastructure.EfCore.Extensions; +using Saritasa.NetForge.Infrastructure.EfCore.Services; +using Saritasa.NetForge.Infrastructure.Helpers; namespace Saritasa.NetForge.Controls.CustomFields; @@ -24,7 +27,6 @@ public IEnumerable PropertyValue private IEnumerable NavigationInstances { get; set; } = null!; - private GetEntityDto EntityMetadata { get; set; } = null!; /// @@ -37,7 +39,14 @@ protected override async Task OnInitializedAsync() NavigationInstances = Service .GetQuery(entityType) .Cast() - .OrderBy(instance => instance); + .OrderBy(instance => instance).ToList(); + + // In case of lazy loading - convert proxies to POCO instances. + if (NavigationInstances.Any() && NavigationInstances.First()!.GetType().IsLazyLoadingProxy()) + { + NavigationInstances = NavigationInstances + .Select(instance => ProxyToPocoConverter.ConvertProxyToPoco(instance)).Cast(); + } EntityMetadata = await EntityService.GetEntityByTypeAsync(entityType, CancellationToken.None); } diff --git a/src/Saritasa.NetForge/Infrastructure/EfCore/Services/EfCoreDataService.cs b/src/Saritasa.NetForge/Infrastructure/EfCore/Services/EfCoreDataService.cs index 28742906..3b81a761 100644 --- a/src/Saritasa.NetForge/Infrastructure/EfCore/Services/EfCoreDataService.cs +++ b/src/Saritasa.NetForge/Infrastructure/EfCore/Services/EfCoreDataService.cs @@ -240,14 +240,7 @@ public async Task UpdateAsync( private async Task UpdateAsync( DbContext dbContext, object entity, object originalEntity, CancellationToken cancellationToken) { - try - { - dbContext.Attach(originalEntity); - } - catch (InvalidOperationException) - { - // Do nothing. It means that entity is already tracked. - } + dbContext.Attach(originalEntity); await UpdateNavigations(dbContext, entity, originalEntity); @@ -302,15 +295,13 @@ private static void UpdateNavigationReference( } else { - try + var isTracked = dbContext.IsTracked(navigationEntry.CurrentValue!, comparer); + + if (!isTracked) { dbContext.Attach(navigationEntry.CurrentValue!); + originalNavigationEntry.CurrentValue = navigationEntry.CurrentValue; } - catch (InvalidOperationException) - { - // Do nothing. It means that entity is already tracked. - } - originalNavigationEntry.CurrentValue = navigationEntry.CurrentValue; } } @@ -325,14 +316,12 @@ private static void UpdateNavigationCollection( // Track added elements foreach (var element in navigationCollectionInstance) { - try + var isTracked = dbContext.IsTracked(element, comparer); + + if (!isTracked) { dbContext.Attach(element); } - catch (InvalidOperationException) - { - // Do nothing. It means that entity is already tracked. - } } var originalNavigationCollectionInstance = (IEnumerable)originalNavigationEntry.CurrentValue!; diff --git a/src/Saritasa.NetForge/Infrastructure/EfCore/Services/ProxyToPocoConverter.cs b/src/Saritasa.NetForge/Infrastructure/EfCore/Services/ProxyToPocoConverter.cs index 5ba18bf7..9e68bd01 100644 --- a/src/Saritasa.NetForge/Infrastructure/EfCore/Services/ProxyToPocoConverter.cs +++ b/src/Saritasa.NetForge/Infrastructure/EfCore/Services/ProxyToPocoConverter.cs @@ -14,7 +14,7 @@ public static class ProxyToPocoConverter /// The source proxy entity. /// The list of navigation property names. /// The POCO entity. - public static object? ConvertProxyToPoco(object? source, IList? navigationPropertyNames) + public static object? ConvertProxyToPoco(object? source, IList? navigationPropertyNames = null) { switch (source) { @@ -33,7 +33,7 @@ public static class ProxyToPocoConverter foreach (var item in sourceCollection) { - pocoCollection.Add(ConvertProxyToPoco(item, null)); + pocoCollection.Add(ConvertProxyToPoco(item)); } return pocoCollection; } @@ -103,7 +103,7 @@ public static class ProxyToPocoConverter continue; } - var navigationPoco = ConvertProxyToPoco(propertyValue, null); + var navigationPoco = ConvertProxyToPoco(propertyValue); entityType.GetProperty(navigationName)?.SetValue(pocoInstance, navigationPoco); }