Skip to content

Commit

Permalink
Fixed issue dotnet#35528
Browse files Browse the repository at this point in the history
  • Loading branch information
henriquewr committed Jan 25, 2025
1 parent 49e724a commit 9a01a46
Showing 1 changed file with 79 additions and 42 deletions.
121 changes: 79 additions & 42 deletions src/EFCore/Infrastructure/Internal/LazyLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Internal;

namespace Microsoft.EntityFrameworkCore.Infrastructure.Internal;
Expand All @@ -20,7 +21,7 @@ public class LazyLoader : ILazyLoader, IInjectableService
private bool _disposed;
private bool _detached;
private IDictionary<string, bool>? _loadedStates;
private readonly ConcurrentDictionary<(object Entity, string NavigationName), bool> _isLoading = new(NavEntryEqualityComparer.Instance);
private readonly ConcurrentDictionary<(object Entity, string NavigationName), T> _isLoading = new(NavEntryEqualityComparer.Instance);
private HashSet<string>? _nonLazyNavigations;

/// <summary>
Expand Down Expand Up @@ -107,31 +108,49 @@ public virtual void Load(object entity, [CallerMemberName] string navigationName
Check.NotEmpty(navigationName, nameof(navigationName));

var navEntry = (entity, navigationName);
if (_isLoading.TryAdd(navEntry, true))

var willWait = true;
TaskCompletionSource taskCompletionSource;

lock (_lock)
{
taskCompletionSource = _isLoading.GetOrAdd(navEntry, x =>
{
willWait = false;
return new TaskCompletionSource();
});
}

if (willWait)
{
taskCompletionSource.Task.Wait();

return;
}

try
{
try
// ShouldLoad is called after _isLoading.Add because it could attempt to load the property. See #13138.
if (ShouldLoad(entity, navigationName, out var entry))
{
// ShouldLoad is called after _isLoading.Add because it could attempt to load the property. See #13138.
if (ShouldLoad(entity, navigationName, out var entry))
try
{
try
{
entry.Load(
_queryTrackingBehavior == QueryTrackingBehavior.NoTrackingWithIdentityResolution
? LoadOptions.ForceIdentityResolution
: LoadOptions.None);
}
catch
{
entry.IsLoaded = false;
throw;
}
entry.Load(
_queryTrackingBehavior == QueryTrackingBehavior.NoTrackingWithIdentityResolution
? LoadOptions.ForceIdentityResolution
: LoadOptions.None);
}
catch
{
entry.IsLoaded = false;
throw;
}
}
finally
{
_isLoading.TryRemove(navEntry, out _);
}
}
finally
{
taskCompletionSource.SetResult();
_isLoading.TryRemove(navEntry, out _);
}
}

Expand All @@ -150,32 +169,50 @@ public virtual async Task LoadAsync(
Check.NotEmpty(navigationName, nameof(navigationName));

var navEntry = (entity, navigationName);
if (_isLoading.TryAdd(navEntry, true))

var willWait = true;
TaskCompletionSource taskCompletionSource;

lock (_lock)
{
taskCompletionSource = _isLoading.GetOrAdd(navEntry, x =>
{
willWait = false;
return new TaskCompletionSource();
});
}

if (willWait)
{
await taskCompletionSource.Task.WaitAsync(cancellationToken).ConfigureAwait(false);

return;
}

try
{
try
// ShouldLoad is called after _isLoading.Add because it could attempt to load the property. See #13138.
if (ShouldLoad(entity, navigationName, out var entry))
{
// ShouldLoad is called after _isLoading.Add because it could attempt to load the property. See #13138.
if (ShouldLoad(entity, navigationName, out var entry))
try
{
try
{
await entry.LoadAsync(
_queryTrackingBehavior == QueryTrackingBehavior.NoTrackingWithIdentityResolution
? LoadOptions.ForceIdentityResolution
: LoadOptions.None,
cancellationToken).ConfigureAwait(false);
}
catch
{
entry.IsLoaded = false;
throw;
}
await entry.LoadAsync(
_queryTrackingBehavior == QueryTrackingBehavior.NoTrackingWithIdentityResolution
? LoadOptions.ForceIdentityResolution
: LoadOptions.None,
cancellationToken).ConfigureAwait(false);
}
catch
{
entry.IsLoaded = false;
throw;
}
}
finally
{
_isLoading.TryRemove(navEntry, out _);
}
}
finally
{
taskCompletionSource.SetResult();
_isLoading.TryRemove(navEntry, out _);
}
}

Expand Down

0 comments on commit 9a01a46

Please sign in to comment.