private StrongReferenceContainer RegisterPrefetch(IEnumerable <Key> keys, IHasNestedNodes fieldContainer, Guid enumerationId)
        {
            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(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);
        }
        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);
            }
        }
        private async ValueTask <StrongReferenceContainer> Prefetch(
            Key key, TypeInfo type, IList <PrefetchFieldDescriptor> descriptors, bool isAsync, CancellationToken token)
        {
            ArgumentValidator.EnsureArgumentNotNull(key, nameof(key));
            ArgumentValidator.EnsureArgumentNotNull(descriptors, nameof(descriptors));

            if (descriptors.Count == 0)
            {
                return(null);
            }
            try {
                EnsureKeyTypeCorrespondsToSpecifiedType(key, type);

                var currentKey = key;
                if (!TryGetTupleOfNonRemovedEntity(ref currentKey, out var ownerState))
                {
                    return(null);
                }

                var selectedFields = descriptors;
                var currentType    = type;
                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 = await ExecuteTasks(false, isAsync, token).ConfigureAwait(false);
                }

                if (referenceContainer != null)
                {
                    _ = referenceContainer.JoinIfPossible(container);
                    return(referenceContainer);
                }
                return(container);
            }
            catch {
                CancelTasks();
                throw;
            }
        }
Exemplo n.º 4
0
        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);
        }