public StrongReferenceContainer Prefetch(Key key, TypeInfo type, IList <PrefetchFieldDescriptor> descriptors) { ArgumentValidator.EnsureArgumentNotNull(key, "key"); ArgumentValidator.EnsureArgumentNotNull(descriptors, "fields"); if (descriptors.Count == 0) { return(null); } try { EnsureKeyTypeCorrespondsToSpecifiedType(key, type); EntityState ownerState; var currentKey = key; if (!TryGetTupleOfNonRemovedEntity(ref currentKey, out ownerState)) { return(null); } var selectedFields = descriptors; var currentType = type; StrongReferenceContainer hierarchyRootContainer = null; var isKeyTypeExact = currentKey.HasExactType || currentKey.TypeReference.Type.IsLeaf || currentKey.TypeReference.Type == type; if (isKeyTypeExact) { currentType = currentKey.TypeReference.Type; EnsureAllFieldsBelongToSpecifiedType(descriptors, currentType); } else { ArgumentValidator.EnsureArgumentNotNull(currentType, "type"); EnsureAllFieldsBelongToSpecifiedType(descriptors, currentType); SetUpContainers(currentKey, currentKey.TypeReference.Type, PrefetchHelper.GetCachedDescriptorsForFieldsLoadedByDefault(session.Domain, currentKey.TypeReference.Type), true, ownerState, true); var hierarchyRoot = currentKey.TypeReference.Type; selectedFields = descriptors .Where(descriptor => descriptor.Field.DeclaringType != hierarchyRoot) .ToList(); } SetUpContainers(currentKey, currentType, selectedFields, isKeyTypeExact, ownerState, ReferenceEquals(descriptors, selectedFields)); StrongReferenceContainer container = null; if (graphContainers.Count >= MaxContainerCount) { container = ExecuteTasks(); } if (referenceContainer != null) { referenceContainer.JoinIfPossible(container); return(referenceContainer); } return(container); } catch { CancelTasks(); throw; } }
/// <summary> /// Joins this instance with <paramref name="other"/>. /// </summary> /// <param name="other">The other container.</param> public bool Join(StrongReferenceContainer other) { if (other == null) { return(false); } if (!IsRoot) { root.Join(other); return(true); } if (!other.IsRoot) { throw new InvalidOperationException(); } other.root = this; if (lastJoinedContainer == null) { nextJoinedContainer = other; } else if (lastJoinedContainer.nextJoinedContainer != null) { throw new InvalidOperationException(); } else { lastJoinedContainer.nextJoinedContainer = other; } lastJoinedContainer = other.lastJoinedContainer ?? other; return(true); }
public void SaveStrongReference(EntityState reference) { if (referenceContainer == null) { referenceContainer = new StrongReferenceContainer(null); } _ = referenceContainer.Join(new StrongReferenceContainer(reference)); }
public IEnumerator <T> GetEnumerator() { TypeInfo modelType; session.Domain.Model.Types.TryGetValue(typeof(T), out modelType); var taskCount = session.Handler.PrefetchTaskExecutionCount; var container = new StrongReferenceContainer(null); var fieldDescriptors = new List <PrefetchFieldDescriptor>(); var resultQueue = new Queue <Key>(); var unknownTypeQueue = new Queue <Key>(); var se = source.GetEnumerator(); bool exists; do { exists = se.MoveNext(); if (exists) { var key = se.Current; var type = key.HasExactType || modelType == null ? key.TypeReference.Type : modelType; if (!key.HasExactType && !type.IsLeaf) { unknownTypeQueue.Enqueue(key); } resultQueue.Enqueue(key); var defaultDescriptors = PrefetchHelper.GetCachedDescriptorsForFieldsLoadedByDefault(session.Domain, type); container.JoinIfPossible(session.Handler.Prefetch(key, type, defaultDescriptors)); } if (exists && taskCount == session.Handler.PrefetchTaskExecutionCount) { continue; } if (!exists) { container.JoinIfPossible(session.Handler.ExecutePrefetchTasks()); } if (unknownTypeQueue.Count > 0) { while (unknownTypeQueue.Count > 0) { var unknownKey = unknownTypeQueue.Dequeue(); var unknownType = session.EntityStateCache[unknownKey, false].Type; var unknownDescriptors = PrefetchHelper.GetCachedDescriptorsForFieldsLoadedByDefault(session.Domain, unknownType); session.Handler.Prefetch(unknownKey, unknownType, unknownDescriptors); } session.Handler.ExecutePrefetchTasks(); } while (resultQueue.Count > 0) { yield return((T)(IEntity)session.EntityStateCache[resultQueue.Dequeue(), true].Entity); } taskCount = session.Handler.PrefetchTaskExecutionCount; } while (exists); }
/// <summary> /// Joins this instance with <paramref name="other"/>, /// if <paramref name="other"/> is not <see langword="null" /> and is the root of other containers' chain. /// </summary> /// <param name="other">The other container.</param> public bool JoinIfPossible(StrongReferenceContainer other) { if (other == null) { return(false); } if (other.IsRoot) { Join(other); } return(true); }
public IEnumerator <TItem> GetEnumerator() { var currentTaskCount = sessionHandler.PrefetchTaskExecutionCount; var aggregatedNodes = NodeAggregator <TItem> .Aggregate(nodes); var resultQueue = new Queue <TItem>(); var container = new StrongReferenceContainer(null); foreach (var item in source) { resultQueue.Enqueue(item); if (item != null) { foreach (var extractorNode in aggregatedNodes) { container.JoinIfPossible(RegisterPrefetch(extractorNode.ExtractKeys(item), extractorNode)); } } if (currentTaskCount == sessionHandler.PrefetchTaskExecutionCount) { continue; } while (container.JoinIfPossible(sessionHandler.ExecutePrefetchTasks())) { container.JoinIfPossible(ProcessFetchedElements()); } while (resultQueue.TryDequeue(out var resultItem)) { yield return(resultItem); } currentTaskCount = sessionHandler.PrefetchTaskExecutionCount; } while (container.JoinIfPossible(sessionHandler.ExecutePrefetchTasks())) { container.JoinIfPossible(ProcessFetchedElements()); } while (resultQueue.TryDequeue(out var resultItem)) { yield return(resultItem); } }
private async Task <StrongReferenceContainer> RegisterPrefetchAsync(IReadOnlyCollection <Key> keys, IHasNestedNodes fieldContainer, Guid enumerationId, CancellationToken token) { var container = new StrongReferenceContainer(null); TypeInfo modelType = null; if (fieldContainer is ReferenceNode refNode) { modelType = refNode.ReferenceType; } foreach (var key in keys) { var type = key.HasExactType || modelType == null ? key.TypeReference.Type : modelType; if (!key.HasExactType && !type.IsLeaf) { unknownTypeQueue.Enqueue(key); } var cacheKey = new Pair <IHasNestedNodes, TypeInfo>(fieldContainer, type); if (!fieldDescriptorCache.TryGetValue(cacheKey, out var fieldDescriptors)) { fieldDescriptors = PrefetchHelper .GetCachedDescriptorsForFieldsLoadedByDefault(session.Domain, type) .Concat(fieldContainer.NestedNodes.Select(fn => new PrefetchFieldDescriptor(fn.Field, false, true, enumerationId))) .ToList(); fieldDescriptorCache.Add(cacheKey, fieldDescriptors); } _ = container.JoinIfPossible( await sessionHandler.PrefetchAsync(key, type, fieldDescriptors, token).ConfigureAwait(false)); } var nestedContainers = fieldContainer.NestedNodes.OfType <IHasNestedNodes>(); foreach (var nestedContainer in nestedContainers) { prefetchQueue.Enqueue(new Pair <IEnumerable <Key>, IHasNestedNodes>(keys, nestedContainer)); } return(container); }
public StrongReferenceContainer ExecuteTasks(bool skipPersist) { if (graphContainers.Count == 0) { referenceContainer = null; return(null); } try { var batchExecuted = fetcher.ExecuteTasks(graphContainers, skipPersist); TaskExecutionCount += batchExecuted; foreach (var graphContainer in graphContainers) { graphContainer.NotifyAboutExtractionOfKeysWithUnknownType(); } return(referenceContainer); } finally { CancelTasks(); } }
private async ValueTask <StrongReferenceContainer> ExecuteTasks(bool skipPersist, bool isAsync, CancellationToken token) { if (graphContainers.Count == 0) { referenceContainer = null; return(null); } try { var batchExecuted = await fetcher.ExecuteTasks(graphContainers, skipPersist, isAsync, token).ConfigureAwait(false); TaskExecutionCount += batchExecuted; foreach (var graphContainer in graphContainers) { graphContainer.NotifyAboutExtractionOfKeysWithUnknownType(); } return(referenceContainer); } finally { CancelTasks(); } }
private StrongReferenceContainer RegisterPrefetch(IEnumerable <Key> keys, IHasNestedNodes fieldContainer) { var container = new StrongReferenceContainer(null); TypeInfo modelType = null; var refNode = fieldContainer as ReferenceNode; if (refNode != null) { modelType = refNode.ReferenceType; } foreach (var key in keys) { var type = key.HasExactType || modelType == null ? key.TypeReference.Type : modelType; if (!key.HasExactType && !type.IsLeaf) { unknownTypeQueue.Enqueue(key); } IList <PrefetchFieldDescriptor> fieldDescriptors; var cacheKey = new Pair <IHasNestedNodes, TypeInfo>(fieldContainer, type); if (!fieldDescriptorCache.TryGetValue(cacheKey, out fieldDescriptors)) { fieldDescriptors = PrefetchHelper .GetCachedDescriptorsForFieldsLoadedByDefault(session.Domain, type) .Concat(fieldContainer.NestedNodes.Select(fn => new PrefetchFieldDescriptor(fn.Field, false, true))).ToList(); fieldDescriptorCache.Add(cacheKey, fieldDescriptors); } container.JoinIfPossible(sessionHandler.Prefetch(key, type, fieldDescriptors)); } var nestedContainers = fieldContainer.NestedNodes.OfType <IHasNestedNodes>(); foreach (var nestedContainer in nestedContainers) { prefetchQueue.Enqueue(new Pair <IEnumerable <Key>, IHasNestedNodes>(keys, nestedContainer)); } return(container); }
private async Task <StrongReferenceContainer> ProcessFetchedElementsAsync(Guid enumerationId, CancellationToken token) { var container = new StrongReferenceContainer(null); while (unknownTypeQueue.TryDequeue(out var unknownKey)) { var unknownType = session.EntityStateCache[unknownKey, false].Type; var unknownDescriptors = PrefetchHelper.GetCachedDescriptorsForFieldsLoadedByDefault(session.Domain, unknownType); _ = await sessionHandler.PrefetchAsync(unknownKey, unknownType, unknownDescriptors, token).ConfigureAwait(false); } while (prefetchQueue.TryDequeue(out var pair)) { var parentKeys = pair.First; var nestedNodes = pair.Second; var keys = new List <Key>(); foreach (var parentKey in parentKeys) { var entityState = session.EntityStateCache[parentKey, false]; if (entityState == null) { _ = container.JoinIfPossible(await sessionHandler.ExecutePrefetchTasksAsync(true, token).ConfigureAwait(false)); entityState = session.EntityStateCache[parentKey, false]; if (entityState == null) { throw new InvalidOperationException(string.Format(Strings.ExCannotResolveEntityWithKeyX, parentKey)); } } keys.AddRange(nestedNodes.ExtractKeys(entityState.Entity)); } _ = container.JoinIfPossible(await RegisterPrefetchAsync(keys, nestedNodes, enumerationId, token).ConfigureAwait(false)); } return(container); }
private StrongReferenceContainer ProcessFetchedElements() { var container = new StrongReferenceContainer(null); taskCount = sessionHandler.PrefetchTaskExecutionCount; while (unknownTypeQueue.Count > 0) { var unknownKey = unknownTypeQueue.Dequeue(); var unknownType = session.EntityStateCache[unknownKey, false].Type; var unknownDescriptors = PrefetchHelper.GetCachedDescriptorsForFieldsLoadedByDefault(session.Domain, unknownType); sessionHandler.Prefetch(unknownKey, unknownType, unknownDescriptors); } while (prefetchQueue.Count > 0) { var pair = prefetchQueue.Dequeue(); var parentKeys = pair.First; var nestedNodes = pair.Second; var keys = new List <Key>(); foreach (var parentKey in parentKeys) { var entityState = session.EntityStateCache[parentKey, false]; if (entityState == null) { container.JoinIfPossible(sessionHandler.ExecutePrefetchTasks(true)); taskCount = sessionHandler.PrefetchTaskExecutionCount; entityState = session.EntityStateCache[parentKey, false]; if (entityState == null) { throw new InvalidOperationException(string.Format(Strings.ExCannotResolveEntityWithKeyX, parentKey)); } } keys.AddRange(nestedNodes.ExtractKeys(entityState.Entity)); } container.JoinIfPossible(RegisterPrefetch(keys, nestedNodes)); } return(container); }
public async IAsyncEnumerator <TItem> GetAsyncEnumerator(CancellationToken token = default) { var currentTaskCount = sessionHandler.PrefetchTaskExecutionCount; var aggregatedNodes = NodeAggregator <TItem> .Aggregate(nodes); var resultQueue = new Queue <TItem>(); strongReferenceContainer = new StrongReferenceContainer(null); var enumerationIdentifier = Guid.NewGuid(); async IAsyncEnumerable <TItem> ProcessItem(TItem item1) { resultQueue.Enqueue(item1); if (item1 != null) { foreach (var extractorNode in aggregatedNodes) { var fetchedItems = await RegisterPrefetchAsync(extractorNode.ExtractKeys(item1), extractorNode, enumerationIdentifier, token).ConfigureAwait(false); _ = strongReferenceContainer.JoinIfPossible(fetchedItems); } } if (currentTaskCount == sessionHandler.PrefetchTaskExecutionCount) { yield break; } while (strongReferenceContainer.JoinIfPossible( await sessionHandler.ExecutePrefetchTasksAsync(token).ConfigureAwait(false))) { _ = strongReferenceContainer.JoinIfPossible(await ProcessFetchedElementsAsync(enumerationIdentifier, token).ConfigureAwait(false)); } while (resultQueue.TryDequeue(out var resultItem)) { yield return(resultItem); } currentTaskCount = sessionHandler.PrefetchTaskExecutionCount; } if (source is IAsyncEnumerable <TItem> asyncItemSource) { await foreach (var item in asyncItemSource.WithCancellation(token).ConfigureAwait(false)) { await foreach (var p in ProcessItem(item).WithCancellation(token).ConfigureAwait(false)) { yield return(p); } } } else { var items = source is IQueryable <TItem> queryableSource ? await queryableSource.ExecuteAsync(token).ConfigureAwait(false) : source; foreach (var item in items) { await foreach (var p in ProcessItem(item).WithCancellation(token).ConfigureAwait(false)) { yield return(p); } } } while (strongReferenceContainer.JoinIfPossible( await sessionHandler.ExecutePrefetchTasksAsync(token).ConfigureAwait(false))) { _ = strongReferenceContainer.JoinIfPossible(await ProcessFetchedElementsAsync(enumerationIdentifier, token).ConfigureAwait(false)); } while (resultQueue.TryDequeue(out var resultItem)) { yield return(resultItem); } }
public void CancelTasks() { referenceContainer = null; graphContainers.Clear(); }
public async IAsyncEnumerator <T> GetAsyncEnumerator(CancellationToken token = default) { session.Domain.Model.Types.TryGetValue(typeof(T), out var modelType); var taskCount = session.Handler.PrefetchTaskExecutionCount; var container = new StrongReferenceContainer(null); var resultQueue = new Queue <Key>(); var unknownTypeQueue = new Queue <Key>(); using var se = source.GetEnumerator(); bool exists; do { exists = se.MoveNext(); if (exists) { var key = se.Current; var type = key.HasExactType || modelType == null ? key.TypeReference.Type : modelType; if (!key.HasExactType && !type.IsLeaf) { unknownTypeQueue.Enqueue(key); } resultQueue.Enqueue(key); var defaultDescriptors = PrefetchHelper.GetCachedDescriptorsForFieldsLoadedByDefault(session.Domain, type); container.JoinIfPossible( await session.Handler.PrefetchAsync(key, type, defaultDescriptors, token).ConfigureAwait(false)); } if (exists && taskCount == session.Handler.PrefetchTaskExecutionCount) { continue; } if (!exists) { container.JoinIfPossible( await session.Handler.ExecutePrefetchTasksAsync(token).ConfigureAwait(false)); } if (unknownTypeQueue.Count > 0) { while (unknownTypeQueue.Count > 0) { var unknownKey = unknownTypeQueue.Dequeue(); var unknownType = session.EntityStateCache[unknownKey, false].Type; var unknownDescriptors = PrefetchHelper.GetCachedDescriptorsForFieldsLoadedByDefault(session.Domain, unknownType); await session.Handler.PrefetchAsync( unknownKey, unknownType, unknownDescriptors, token).ConfigureAwait(false); } await session.Handler.ExecutePrefetchTasksAsync(token).ConfigureAwait(false); } while (resultQueue.Count > 0) { yield return((T)(IEntity)session.EntityStateCache[resultQueue.Dequeue(), true].Entity); } taskCount = session.Handler.PrefetchTaskExecutionCount; } while (exists); }