// ReSharper disable once InconsistentNaming private static IAsyncEnumerable <TElement> _InjectParameters <TElement>( QueryContext queryContext, IAsyncEnumerable <TElement> source, string[] parameterNames, object[] parameterValues) => new ParameterInjector <TElement>(queryContext, source, parameterNames, parameterValues);
private static void PopulateCollection <TCollection, TElement, TRelatedEntity>( int collectionId, QueryContext queryContext, DbDataReader dbDataReader, ResultCoordinator resultCoordinator, Func <QueryContext, DbDataReader, object[]> parentIdentifier, Func <QueryContext, DbDataReader, object[]> outerIdentifier, Func <QueryContext, DbDataReader, object[]> selfIdentifier, Func <QueryContext, DbDataReader, ResultContext, ResultCoordinator, TRelatedEntity> innerShaper) where TRelatedEntity : TElement where TCollection : class, ICollection <TElement> { var collectionMaterializationContext = resultCoordinator.Collections[collectionId]; if (collectionMaterializationContext.Collection is null) { // nothing to materialize since no collection created return; } if (resultCoordinator.HasNext == false) { // Outer Enumerator has ended GenerateCurrentElementIfPending(); return; } if (!StructuralComparisons.StructuralEqualityComparer.Equals( outerIdentifier(queryContext, dbDataReader), collectionMaterializationContext.OuterIdentifier)) { // Outer changed so collection has ended. Materialize last element. GenerateCurrentElementIfPending(); // If parent also changed then this row is now pointing to element of next collection if (!StructuralComparisons.StructuralEqualityComparer.Equals( parentIdentifier(queryContext, dbDataReader), collectionMaterializationContext.ParentIdentifier)) { resultCoordinator.HasNext = true; } return; } var innerKey = selfIdentifier(queryContext, dbDataReader); if (innerKey.Any(e => e == null)) { // No correlated element return; } if (collectionMaterializationContext.SelfIdentifier != null) { if (StructuralComparisons.StructuralEqualityComparer.Equals( innerKey, collectionMaterializationContext.SelfIdentifier)) { // repeated row for current element // If it is pending materialization then it may have nested elements if (collectionMaterializationContext.ResultContext.Values != null) { ProcessCurrentElementRow(); } resultCoordinator.ResultReady = false; return; } // Row for new element which is not first element // So materialize the element GenerateCurrentElementIfPending(); resultCoordinator.HasNext = null; collectionMaterializationContext.UpdateSelfIdentifier(innerKey); } else { // First row for current element collectionMaterializationContext.UpdateSelfIdentifier(innerKey); } ProcessCurrentElementRow(); resultCoordinator.ResultReady = false; void ProcessCurrentElementRow() { var previousResultReady = resultCoordinator.ResultReady; resultCoordinator.ResultReady = true; var element = innerShaper( queryContext, dbDataReader, collectionMaterializationContext.ResultContext, resultCoordinator); if (resultCoordinator.ResultReady) { // related element is materialized collectionMaterializationContext.ResultContext.Values = null; ((TCollection)collectionMaterializationContext.Collection).Add(element); } resultCoordinator.ResultReady &= previousResultReady; } void GenerateCurrentElementIfPending() { if (collectionMaterializationContext.ResultContext.Values != null) { resultCoordinator.HasNext = false; ProcessCurrentElementRow(); } collectionMaterializationContext.UpdateSelfIdentifier(null); } }
private static IRelatedEntitiesLoader _CreateCollectionRelatedEntitiesLoader( QueryContext queryContext, ShaperCommandContext shaperCommandContext, int queryIndex, Func <ValueBuffer, object> materializer) => new CollectionRelatedEntitiesLoader(queryContext, shaperCommandContext, queryIndex, materializer);
private static void PopulateIncludeCollection <TIncludingEntity, TIncludedEntity>( int collectionId, QueryContext queryContext, DbDataReader dbDataReader, ResultCoordinator resultCoordinator, Func <QueryContext, DbDataReader, object[]> parentIdentifier, Func <QueryContext, DbDataReader, object[]> outerIdentifier, Func <QueryContext, DbDataReader, object[]> selfIdentifier, Func <QueryContext, DbDataReader, ResultContext, ResultCoordinator, TIncludedEntity> innerShaper, INavigation inverseNavigation, Action <TIncludingEntity, TIncludedEntity> fixup, bool trackingQuery) { var collectionMaterializationContext = resultCoordinator.Collections[collectionId]; if (collectionMaterializationContext.Parent is TIncludingEntity entity) { if (resultCoordinator.HasNext == false) { // Outer Enumerator has ended GenerateCurrentElementIfPending(); return; } if (!StructuralComparisons.StructuralEqualityComparer.Equals( outerIdentifier(queryContext, dbDataReader), collectionMaterializationContext.OuterIdentifier)) { // Outer changed so collection has ended. Materialize last element. GenerateCurrentElementIfPending(); // If parent also changed then this row is now pointing to element of next collection if (!StructuralComparisons.StructuralEqualityComparer.Equals( parentIdentifier(queryContext, dbDataReader), collectionMaterializationContext.ParentIdentifier)) { resultCoordinator.HasNext = true; } return; } var innerKey = selfIdentifier(queryContext, dbDataReader); if (innerKey.Any(e => e == null)) { // No correlated element return; } if (collectionMaterializationContext.SelfIdentifier != null) { if (StructuralComparisons.StructuralEqualityComparer.Equals( innerKey, collectionMaterializationContext.SelfIdentifier)) { // repeated row for current element // If it is pending materialization then it may have nested elements if (collectionMaterializationContext.ResultContext.Values != null) { ProcessCurrentElementRow(); } resultCoordinator.ResultReady = false; return; } // Row for new element which is not first element // So materialize the element GenerateCurrentElementIfPending(); resultCoordinator.HasNext = null; collectionMaterializationContext.UpdateSelfIdentifier(innerKey); } else { // First row for current element collectionMaterializationContext.UpdateSelfIdentifier(innerKey); } ProcessCurrentElementRow(); resultCoordinator.ResultReady = false; } void ProcessCurrentElementRow() { var previousResultReady = resultCoordinator.ResultReady; resultCoordinator.ResultReady = true; var relatedEntity = innerShaper( queryContext, dbDataReader, collectionMaterializationContext.ResultContext, resultCoordinator); if (resultCoordinator.ResultReady) { // related entity is materialized collectionMaterializationContext.ResultContext.Values = null; if (!trackingQuery) { fixup(entity, relatedEntity); if (inverseNavigation != null) { SetIsLoadedNoTracking(relatedEntity, inverseNavigation); } } } resultCoordinator.ResultReady &= previousResultReady; } void GenerateCurrentElementIfPending() { if (collectionMaterializationContext.ResultContext.Values != null) { resultCoordinator.HasNext = false; ProcessCurrentElementRow(); } collectionMaterializationContext.UpdateSelfIdentifier(null); } }