Пример #1
0
        private static async Task <ICollection <TEntity> > MaterializeCollectionNavigationAsync <TEntity>(
            INavigation navigation,
            IAsyncEnumerable <object> elements,
            CancellationToken cancellationToken)
        {
            var collection = (ICollection <TEntity>)navigation.GetCollectionAccessor().Create();

            await elements.ForEachAsync(e => collection.Add((TEntity)e), cancellationToken);

            return(collection);
        }
Пример #2
0
 private static Expression AddToCollectionNavigation(
     ParameterExpression entity,
     ParameterExpression relatedEntity,
     INavigation navigation)
 {
     return(Expression.Call(
                Expression.Constant(navigation.GetCollectionAccessor()),
                _collectionAccessorAddMethodInfo,
                entity,
                relatedEntity));
 }
        private static INotifyCollectionChanged AsINotifyCollectionChanged(
            InternalEntityEntry entry,
            INavigation navigation,
            IEntityType entityType,
            ChangeTrackingStrategy changeTrackingStrategy)
        {
            if (!(navigation.GetCollectionAccessor()?.GetOrCreate(entry.Entity) is INotifyCollectionChanged notifyingCollection))
            {
                throw new InvalidOperationException(
                          CoreStrings.NonNotifyingCollection(navigation.Name, entityType.DisplayName(), changeTrackingStrategy));
            }

            return(notifyingCollection);
        }
Пример #4
0
        private static Expression InjectSubquery(Expression expression, INavigation collectionNavigation)
        {
            var targetType     = collectionNavigation.GetTargetType().ClrType;
            var mainFromClause = new MainFromClause(targetType.Name.Substring(0, 1).ToLowerInvariant(), targetType, expression);
            var selector       = new QuerySourceReferenceExpression(mainFromClause);

            var subqueryModel      = new QueryModel(mainFromClause, new SelectClause(selector));
            var subqueryExpression = new SubQueryExpression(subqueryModel);

            var resultCollectionType = collectionNavigation.GetCollectionAccessor().CollectionType;

            var result = Expression.Call(
                MaterializeCollectionNavigationMethodInfo.MakeGenericMethod(targetType),
                Expression.Constant(collectionNavigation), subqueryExpression);

            return(resultCollectionType.GetTypeInfo().IsGenericType&& resultCollectionType.GetGenericTypeDefinition() == typeof(ICollection <>)
                ? (Expression)result
                : Expression.Convert(result, resultCollectionType));
        }
Пример #5
0
            private static void IncludeCollection <TEntity, TIncludingEntity, TIncludedEntity>(
                QueryContext queryContext,
                IEnumerable <ValueBuffer> innerValueBuffers,
                Func <QueryContext, ValueBuffer, TIncludedEntity> innerShaper,
                TEntity entity,
                INavigation navigation,
                INavigation inverseNavigation,
                Action <TIncludingEntity, TIncludedEntity> fixup,
                bool trackingQuery)
                where TIncludingEntity : class, TEntity
                where TEntity : class
                where TIncludedEntity : class
            {
                if (entity is TIncludingEntity includingEntity)
                {
                    var collectionAccessor = navigation.GetCollectionAccessor();
                    collectionAccessor.GetOrCreate(includingEntity, forMaterialization: true);

                    if (trackingQuery)
                    {
                        queryContext.SetNavigationIsLoaded(entity, navigation);
                    }
                    else
                    {
                        SetIsLoadedNoTracking(entity, navigation);
                    }

                    foreach (var valueBuffer in innerValueBuffers)
                    {
                        var relatedEntity = innerShaper(queryContext, valueBuffer);

                        if (!trackingQuery)
                        {
                            fixup(includingEntity, relatedEntity);
                            if (inverseNavigation != null)
                            {
                                SetIsLoadedNoTracking(relatedEntity, inverseNavigation);
                            }
                        }
                    }
                }
            }
Пример #6
0
            private static Delegate GenerateInitialize(
                Type entityType,
                INavigation navigation)
            {
                if (!navigation.IsCollection())
                {
                    return(null);
                }

                var entityParameter = Expression.Parameter(entityType);

                var getOrCreateExpression = Expression.Call(
                    Expression.Constant(navigation.GetCollectionAccessor()),
                    _collectionAccessorGetOrCreateMethodInfo,
                    entityParameter,
                    Expression.Constant(true));

                return(Expression.Lambda(Expression.Block(typeof(void), getOrCreateExpression), entityParameter)
                       .Compile());
            }
Пример #7
0
            private static void IncludeCollection <TEntity, TIncludingEntity, TIncludedEntity>(
                QueryContext queryContext,
                TEntity entity,
                IEnumerable <TIncludedEntity> relatedEntities,
                INavigation navigation,
                INavigation inverseNavigation,
                Action <TIncludingEntity, TIncludedEntity> fixup,
                bool trackingQuery)
                where TIncludingEntity : class, TEntity
                where TEntity : class
                where TIncludedEntity : class
            {
                if (entity is TIncludingEntity includingEntity)
                {
                    var collectionAccessor = navigation.GetCollectionAccessor();
                    collectionAccessor.GetOrCreate(includingEntity, forMaterialization: true);

                    if (trackingQuery)
                    {
                        foreach (var relatedEntity in relatedEntities)
                        {
                            collectionAccessor.Add(includingEntity, relatedEntity, forMaterialization: true);
                        }

                        queryContext.SetIsLoaded(includingEntity, navigation);
                    }
                    else
                    {
                        foreach (var relatedEntity in relatedEntities)
                        {
                            fixup(includingEntity, relatedEntity);
                            if (inverseNavigation != null)
                            {
                                SetIsLoadedNoTracking(relatedEntity, inverseNavigation);
                            }
                        }

                        SetIsLoadedNoTracking(includingEntity, navigation);
                    }
                }
            }
Пример #8
0
        private void Unfixup(INavigation navigation, InternalEntityEntry oldPrincipalEntry, InternalEntityEntry dependentEntry)
        {
            if (navigation.IsDependentToPrincipal())
            {
                navigation.GetSetter().SetClrValue(dependentEntry.Entity, null);

                dependentEntry.RelationshipsSnapshot.TakeSnapshot(navigation);
            }
            else
            {
                if (navigation.IsCollection())
                {
                    var collectionAccessor = navigation.GetCollectionAccessor();
                    if (collectionAccessor.Contains(oldPrincipalEntry.Entity, dependentEntry.Entity))
                    {
                        collectionAccessor.Remove(oldPrincipalEntry.Entity, dependentEntry.Entity);
                    }
                }
                else
                {
                    navigation.GetSetter().SetClrValue(oldPrincipalEntry.Entity, null);
                }
            }
        }
Пример #9
0
        private static ICollection <TEntity> MaterializeCollectionNavigation <TEntity>(INavigation navigation, IEnumerable <object> elements)
        {
            var collection = navigation.GetCollectionAccessor().Create(elements);

            return((ICollection <TEntity>)collection);
        }
        public object CreateRealObject(IModel model, ISecurityObjectRepository securityObjectRepository)
        {
            Type targetType = SecurityObject.GetType();

            RealObject = Activator.CreateInstance(SecurityObject.GetType());
            IEntityType entityType = model.FindEntityType(targetType);
            IEnumerable <PropertyInfo> properiesInfo = targetType.GetRuntimeProperties();
            IEnumerable <INavigation>  navigations   = entityType.GetNavigations();

            IReadOnlyList <IProperty> primaryKeyProperties = entityType.FindPrimaryKey().Properties;

            foreach (PropertyInfo propertyInfo in properiesInfo)
            {
                object defaultValue = propertyInfo.GetValue(RealObject);
                defaultValueDictionary[propertyInfo.Name] = defaultValue;
                if (navigations.Any(p => p.Name == propertyInfo.Name))
                {
                    INavigation navigation = navigations.First(p => p.Name == propertyInfo.Name);
                    if (navigation.IsCollection())
                    {
                        IClrCollectionAccessor collectionAccessor              = navigation.GetCollectionAccessor();
                        IEnumerable            realObjectListPropertyValue     = (IEnumerable)propertyInfo.GetValue(RealObject);
                        IEnumerable            securityObjectListPropertyValue = (IEnumerable)propertyInfo.GetValue(SecurityObject);
                        if (securityObjectListPropertyValue != null && realObjectListPropertyValue != null)
                        {
                            foreach (object objectInListProperty in securityObjectListPropertyValue)
                            {
                                SecurityObjectBuilder metadata = securityObjectRepository.GetObjectMetaData(objectInListProperty);
                                if (metadata == null)
                                {
                                    metadata = new SecurityObjectBuilder();
                                    securityObjectRepository.RegisterBuilder(metadata);
                                    metadata.SecurityObject = objectInListProperty;
                                    metadata.CreateRealObject(model, securityObjectRepository);
                                }
                                collectionAccessor.Add(RealObject, metadata.RealObject);
                            }
                        }
                    }
                    else
                    {
                        object realValue = propertyInfo.GetValue(SecurityObject);
                        if (!Equals(realValue, null))
                        {
                            SecurityObjectBuilder metadata = securityObjectRepository.GetObjectMetaData(realValue);
                            if (metadata == null)
                            {
                                metadata = new SecurityObjectBuilder();
                                securityObjectRepository.RegisterBuilder(metadata);
                                metadata.SecurityObject = realValue;

                                metadata.CreateRealObject(model, securityObjectRepository);
                            }
                            if (propertyInfo.SetMethod != null)
                            {
                                propertyInfo.SetValue(RealObject, metadata.RealObject);
                            }
                        }
                    }
                }
                else
                {
                    bool isGeneratedPrimaryKey = false;
                    foreach (IProperty primaryKeyProperty in primaryKeyProperties)
                    {
                        if ((propertyInfo.Name == primaryKeyProperty.Name) && primaryKeyProperty.RequiresValueGenerator)
                        {
                            isGeneratedPrimaryKey = true;
                        }
                    }
                    if (propertyInfo.SetMethod != null && !isGeneratedPrimaryKey)
                    {
                        object securityValue = propertyInfo.GetValue(SecurityObject);
                        propertyInfo.SetValue(RealObject, securityValue);
                    }
                }
            }
            return(RealObject);
        }
Пример #11
0
        /// <summary>
        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used 
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public virtual void NavigationCollectionChanged(
            InternalEntityEntry entry,
            INavigation navigation,
            IEnumerable<object> added,
            IEnumerable<object> removed)
        {
            if (_inFixup)
            {
                return;
            }

            var foreignKey = navigation.ForeignKey;
            var stateManager = entry.StateManager;
            var inverse = navigation.FindInverse();
            var collectionAccessor = navigation.GetCollectionAccessor();

            foreach (var oldValue in removed)
            {
                var oldTargetEntry = stateManager.TryGetEntry(oldValue);

                if (oldTargetEntry != null
                    && oldTargetEntry.EntityState != EntityState.Detached)
                {
                    try
                    {
                        _inFixup = true;

                        // Null FKs and navigations of dependents that have been removed, unless they
                        // have already been changed.
                        ConditionallyNullForeignKeyProperties(oldTargetEntry, entry, foreignKey);

                        if (inverse != null
                            && ReferenceEquals(oldTargetEntry[inverse], entry.Entity))
                        {
                            SetNavigation(oldTargetEntry, inverse, null);
                        }

                        entry.RemoveFromCollectionSnapshot(navigation, oldValue);
                    }
                    finally
                    {
                        _inFixup = false;
                    }
                }
            }

            foreach (var newValue in added)
            {
                var newTargetEntry = stateManager.GetOrCreateEntry(newValue);

                if (newTargetEntry.EntityState != EntityState.Detached)
                {
                    try
                    {
                        _inFixup = true;

                        // For a dependent added to the collection, remove it from the collection of
                        // the principal entity that it was previously part of
                        var oldPrincipalEntry = stateManager.GetPrincipal(newTargetEntry, foreignKey);
                        if (oldPrincipalEntry != null)
                        {
                            RemoveFromCollection(oldPrincipalEntry, navigation, collectionAccessor, newValue);
                        }

                        // Set the FK properties on added dependents to match this principal
                        SetForeignKeyProperties(newTargetEntry, entry, foreignKey, setModified: true);

                        // Set the inverse navigation to point to this principal
                        SetNavigation(newTargetEntry, inverse, entry.Entity);
                    }
                    finally
                    {
                        _inFixup = false;
                    }
                }
                else
                {
                    stateManager.RecordReferencedUntrackedEntity(newValue, navigation, entry);
                    _attacher.AttachGraph(newTargetEntry, EntityState.Added);
                }

                entry.AddToCollectionSnapshot(navigation, newValue);
            }
        }
Пример #12
0
        private void AddRangeToCollection(object entity, INavigation navigation, IEnumerable<object> values, bool tracking)
        {
            navigation.GetCollectionAccessor().AddRange(entity, values);

            if (tracking)
            {
                _stateManager.TryGetEntry(entity)?.AddRangeToCollectionSnapshot(navigation, values);
            }
        }
Пример #13
0
        private void AddToCollection(object entity, INavigation navigation, object value, bool tracking)
        {
            navigation.GetCollectionAccessor().Add(entity, value);

            if (tracking)
            {
                _stateManager.TryGetEntry(entity)?.AddToCollectionSnapshot(navigation, value);
            }
        }
Пример #14
0
        private void DelayedFixup(InternalEntityEntry entry, INavigation navigation, InternalEntityEntry referencedEntry)
        {
            var navigationValue = entry[navigation];

            if (navigationValue != null)
            {
                var setModified = referencedEntry.EntityState != EntityState.Unchanged;

                if (!navigation.IsDependentToPrincipal())
                {
                    if (navigation.IsCollection())
                    {
                        if (navigation.GetCollectionAccessor().Contains(entry.Entity, referencedEntry.Entity))
                        {
                            FixupToDependent(entry, referencedEntry, navigation.ForeignKey, setModified);
                        }
                    }
                    else if (referencedEntry.Entity == navigationValue)
                    {
                        FixupToDependent(entry, referencedEntry, navigation.ForeignKey, setModified);
                    }
                }
                else if (referencedEntry.Entity == navigationValue)
                {
                    FixupToPrincipal(entry, referencedEntry, navigation.ForeignKey, setModified);
                }
            }
        }
Пример #15
0
        private static object TryFindPrincipal(IStateManager stateManager, INavigation navigation, object dependentEntity)
        {
            if (navigation.IsDependentToPrincipal())
            {
                return navigation.GetGetter().GetClrValue(dependentEntity);
            }

            // TODO: Perf
            foreach (var principalEntry in stateManager.Entries.Where(
                e => e.EntityState != EntityState.Detached
                     && navigation.ForeignKey.PrincipalEntityType.IsAssignableFrom(e.EntityType)))
            {
                if (navigation.IsCollection())
                {
                    if (navigation.GetCollectionAccessor().Contains(principalEntry.Entity, dependentEntity))
                    {
                        return principalEntry.Entity;
                    }
                }
                else if (navigation.GetGetter().GetClrValue(principalEntry.Entity) == dependentEntity)
                {
                    return principalEntry.Entity;
                }
            }

            return null;
        }
Пример #16
0
        /// <summary>
        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public virtual void NavigationCollectionChanged(
            InternalEntityEntry entry,
            INavigation navigation,
            IEnumerable <object> added,
            IEnumerable <object> removed)
        {
            if (_inFixup)
            {
                return;
            }

            var foreignKey         = navigation.ForeignKey;
            var stateManager       = entry.StateManager;
            var inverse            = navigation.FindInverse();
            var collectionAccessor = navigation.GetCollectionAccessor();

            foreach (var oldValue in removed)
            {
                var oldTargetEntry = stateManager.TryGetEntry(oldValue);

                if (oldTargetEntry != null &&
                    oldTargetEntry.EntityState != EntityState.Detached)
                {
                    try
                    {
                        _inFixup = true;

                        // Null FKs and navigations of dependents that have been removed, unless they
                        // have already been changed.
                        ConditionallyNullForeignKeyProperties(oldTargetEntry, entry, foreignKey);

                        if (inverse != null &&
                            ReferenceEquals(oldTargetEntry[inverse], entry.Entity))
                        {
                            SetNavigation(oldTargetEntry, inverse, null);
                        }

                        entry.RemoveFromCollectionSnapshot(navigation, oldValue);
                    }
                    finally
                    {
                        _inFixup = false;
                    }
                }
            }

            foreach (var newValue in added)
            {
                var newTargetEntry = stateManager.GetOrCreateEntry(newValue);

                if (newTargetEntry.EntityState != EntityState.Detached)
                {
                    try
                    {
                        _inFixup = true;

                        // For a dependent added to the collection, remove it from the collection of
                        // the principal entity that it was previously part of
                        var oldPrincipalEntry = stateManager.GetPrincipal(newTargetEntry, foreignKey);
                        if (oldPrincipalEntry != null)
                        {
                            RemoveFromCollection(oldPrincipalEntry, navigation, collectionAccessor, newValue);
                        }

                        // Set the FK properties on added dependents to match this principal
                        SetForeignKeyProperties(newTargetEntry, entry, foreignKey, setModified: true);

                        // Set the inverse navigation to point to this principal
                        SetNavigation(newTargetEntry, inverse, entry.Entity);
                    }
                    finally
                    {
                        _inFixup = false;
                    }
                }
                else
                {
                    stateManager.RecordReferencedUntrackedEntity(newValue, navigation, entry);
                    _attacher.AttachGraph(newTargetEntry, EntityState.Added);
                }

                entry.AddToCollectionSnapshot(navigation, newValue);
            }
        }
        private static INotifyCollectionChanged AsINotifyCollectionChanged(
            InternalEntityEntry entry,
            INavigation navigation,
            IEntityType entityType,
            ChangeTrackingStrategy changeTrackingStrategy)
        {
            var notifyingCollection = navigation.GetCollectionAccessor().GetOrCreate(entry.Entity) as INotifyCollectionChanged;
            if (notifyingCollection == null)
            {
                throw new InvalidOperationException(
                    CoreStrings.NonNotifyingCollection(navigation.Name, entityType.DisplayName(), changeTrackingStrategy));
            }

            return notifyingCollection;
        }
Пример #18
0
        private Expression Rewrite(
            int correlatedCollectionIndex,
            QueryModel collectionQueryModel,
            INavigation navigation,
            bool trackingQuery,
            QuerySourceReferenceExpression originQuerySource,
            bool forceListResult)
        {
            var querySourceReferenceFindingExpressionTreeVisitor
                = new QuerySourceReferenceFindingExpressionTreeVisitor();

            var originalCorrelationPredicate = collectionQueryModel.BodyClauses.OfType <WhereClause>().Single(c => c.Predicate is NullConditionalEqualExpression);

            collectionQueryModel.BodyClauses.Remove(originalCorrelationPredicate);

            originalCorrelationPredicate.TransformExpressions(querySourceReferenceFindingExpressionTreeVisitor.Visit);
            var parentQuerySourceReferenceExpression = querySourceReferenceFindingExpressionTreeVisitor.QuerySourceReferenceExpression;

            querySourceReferenceFindingExpressionTreeVisitor = new QuerySourceReferenceFindingExpressionTreeVisitor();
            querySourceReferenceFindingExpressionTreeVisitor.Visit(((NullConditionalEqualExpression)originalCorrelationPredicate.Predicate).InnerKey);

            var currentKey = BuildKeyAccess(navigation.ForeignKey.Properties, querySourceReferenceFindingExpressionTreeVisitor.QuerySourceReferenceExpression);

            // PK of the parent qsre
            var originKey = BuildKeyAccess(_queryCompilationContext.Model.FindEntityType(originQuerySource.Type).FindPrimaryKey().Properties, originQuerySource);

            // principal side of the FK relationship between parent and this collection
            var outerKey = BuildKeyAccess(navigation.ForeignKey.PrincipalKey.Properties, parentQuerySourceReferenceExpression);

            var parentQuerySource = parentQuerySourceReferenceExpression.ReferencedQuerySource;

            // ordering priority for parent:
            // - user specified orderings
            // - parent PK
            // - principal side of the FK between parent and child

            // ordering priority for child:
            // - user specified orderings on parent (from join)
            // - parent PK (from join)
            // - dependent side of the FK between parent and child
            // - customer specified orderings on child

            var parentOrderings            = new List <Ordering>();
            var exisingParentOrderByClause = _parentQueryModel.BodyClauses.OfType <OrderByClause>().LastOrDefault();

            if (exisingParentOrderByClause != null)
            {
                parentOrderings.AddRange(exisingParentOrderByClause.Orderings);
            }

            var originEntityType = _queryCompilationContext.Model.FindEntityType(originQuerySource.Type);

            foreach (var property in originEntityType.FindPrimaryKey().Properties)
            {
                TryAddPropertyToOrderings(property, originQuerySource, parentOrderings);
            }

            foreach (var property in navigation.ForeignKey.PrincipalKey.Properties)
            {
                TryAddPropertyToOrderings(property, parentQuerySourceReferenceExpression, parentOrderings);
            }

            _parentOrderings.AddRange(parentOrderings);

            // if selector contains multiple correlated collections, visiting the first one changes that collections QM (changing it's type)
            // which makes the parent QM inconsistent temporarily. QM's type is different but the CorrelateCollections method that fixes the result type
            // is not part of the QM and it's added only when the entire Selector is replaced - i.e. after all it's components have been visited

            // since when we clone the parent QM, we don't care about it's original selector anyway (it's being discarded)
            // we avoid cloning the selector in the first place and avoid all the potential problem with temporarily mismatched types of the subqueries inside
            var parentSelectClause = _parentQueryModel.SelectClause;

            _parentQueryModel.SelectClause = new SelectClause(Expression.Default(parentSelectClause.Selector.Type));

            var querySourceMapping     = new QuerySourceMapping();
            var clonedParentQueryModel = _parentQueryModel.Clone(querySourceMapping);

            _parentQueryModel.SelectClause = parentSelectClause;

            _queryCompilationContext.UpdateMapping(querySourceMapping);
            _queryCompilationContext.CloneAnnotations(querySourceMapping, clonedParentQueryModel);

            var clonedParentQuerySourceReferenceExpression
                = (QuerySourceReferenceExpression)querySourceMapping.GetExpression(parentQuerySource);

            var clonedParentQuerySource
                = clonedParentQuerySourceReferenceExpression.ReferencedQuerySource;

            var parentItemName
                = parentQuerySource.HasGeneratedItemName()
                    ? navigation.DeclaringEntityType.DisplayName()[0].ToString().ToLowerInvariant()
                    : parentQuerySource.ItemName;

            collectionQueryModel.MainFromClause.ItemName = $"{parentItemName}.{navigation.Name}";

            var collectionQuerySourceReferenceExpression
                = new QuerySourceReferenceExpression(collectionQueryModel.MainFromClause);

            var subQueryProjection = new List <Expression>();

            subQueryProjection.AddRange(parentOrderings.Select(o => CloningExpressionVisitor.AdjustExpressionAfterCloning(o.Expression, querySourceMapping)));

            var joinQuerySourceReferenceExpression
                = CreateJoinToParentQuery(
                      clonedParentQueryModel,
                      clonedParentQuerySourceReferenceExpression,
                      collectionQuerySourceReferenceExpression,
                      navigation.ForeignKey,
                      collectionQueryModel,
                      subQueryProjection);

            ApplyParentOrderings(
                parentOrderings,
                clonedParentQueryModel,
                querySourceMapping);

            LiftOrderBy(
                joinQuerySourceReferenceExpression,
                clonedParentQueryModel,
                collectionQueryModel);

            clonedParentQueryModel.SelectClause.Selector
                = Expression.New(
                      MaterializedAnonymousObject.AnonymousObjectCtor,
                      Expression.NewArrayInit(
                          typeof(object),
                          subQueryProjection.Select(e => Expression.Convert(e, typeof(object)))));

            clonedParentQueryModel.ResultTypeOverride = typeof(IQueryable <>).MakeGenericType(clonedParentQueryModel.SelectClause.Selector.Type);

            var newOriginKey = CloningExpressionVisitor
                               .AdjustExpressionAfterCloning(originKey, querySourceMapping);

            var newOriginKeyElements      = ((NewArrayExpression)(((NewExpression)newOriginKey).Arguments[0])).Expressions;
            var remappedOriginKeyElements = RemapOriginKeyExpressions(newOriginKeyElements, joinQuerySourceReferenceExpression, subQueryProjection);

            var tupleCtor = typeof(Tuple <, ,>).MakeGenericType(
                collectionQueryModel.SelectClause.Selector.Type,
                typeof(MaterializedAnonymousObject),
                typeof(MaterializedAnonymousObject)).GetConstructors().FirstOrDefault();

            var navigationParameter = Expression.Parameter(typeof(INavigation), "n");

            var correlateSubqueryMethod = _queryCompilationContext.IsAsyncQuery
                ? _correlateSubqueryAsyncMethodInfo
                : _correlateSubqueryMethodInfo;

            Expression resultCollectionFactoryExpressionBody;

            if (forceListResult ||
                navigation.ForeignKey.DeclaringEntityType.ClrType != collectionQueryModel.SelectClause.Selector.Type)
            {
                var resultCollectionType = typeof(List <>).MakeGenericType(collectionQueryModel.SelectClause.Selector.Type);
                var resultCollectionCtor = resultCollectionType.GetTypeInfo().GetDeclaredConstructor(new Type[] { });

                correlateSubqueryMethod = correlateSubqueryMethod.MakeGenericMethod(
                    collectionQueryModel.SelectClause.Selector.Type,
                    typeof(List <>).MakeGenericType(collectionQueryModel.SelectClause.Selector.Type));

                resultCollectionFactoryExpressionBody = Expression.New(resultCollectionCtor);

                trackingQuery = false;
            }
            else
            {
                correlateSubqueryMethod = correlateSubqueryMethod.MakeGenericMethod(
                    collectionQueryModel.SelectClause.Selector.Type,
                    navigation.GetCollectionAccessor().CollectionType);

                resultCollectionFactoryExpressionBody
                    = Expression.Convert(
                          Expression.Call(
                              Expression.Call(_getCollectionAccessorMethodInfo, navigationParameter),
                              _createCollectionMethodInfo),
                          navigation.GetCollectionAccessor().CollectionType);
            }

            var resultCollectionFactoryExpression = Expression.Lambda(
                resultCollectionFactoryExpressionBody,
                navigationParameter);

            collectionQueryModel.SelectClause.Selector
                = Expression.New(
                      tupleCtor,
                      new Expression[]
            {
                collectionQueryModel.SelectClause.Selector,
                currentKey,
                Expression.New(
                    MaterializedAnonymousObject.AnonymousObjectCtor,
                    Expression.NewArrayInit(
                        typeof(object),
                        remappedOriginKeyElements))
            });

            var collectionModelSelectorType = collectionQueryModel.SelectClause.Selector.Type;

            // Enumerable or OrderedEnumerable
            collectionQueryModel.ResultTypeOverride = collectionQueryModel.BodyClauses.OfType <OrderByClause>().Any()
                ? typeof(IOrderedEnumerable <>).MakeGenericType(collectionModelSelectorType)
                : typeof(IEnumerable <>).MakeGenericType(collectionModelSelectorType);

            var lambda = (Expression)Expression.Lambda(new SubQueryExpression(collectionQueryModel));

            if (_queryCompilationContext.IsAsyncQuery)
            {
                lambda = Expression.Convert(
                    lambda,
                    typeof(Func <>).MakeGenericType(
                        typeof(IAsyncEnumerable <>).MakeGenericType(collectionModelSelectorType)));
            }

            // since we cloned QM, we need to check if it's query sources require materialization (e.g. TypeIs operation for InMemory)
            _queryCompilationContext.FindQuerySourcesRequiringMaterialization(_queryModelVisitor, collectionQueryModel);

            var correlationPredicate = CreateCorrelationPredicate(navigation);

            var arguments = new List <Expression>
            {
                Expression.Constant(correlatedCollectionIndex),
                Expression.Constant(navigation),
                resultCollectionFactoryExpression,
                outerKey,
                Expression.Constant(trackingQuery),
                lambda,
                correlationPredicate
            };

            if (_queryCompilationContext.IsAsyncQuery)
            {
                arguments.Add(_cancellationTokenParameter);
            }

            var result = Expression.Call(
                Expression.Property(
                    EntityQueryModelVisitor.QueryContextParameter,
                    nameof(QueryContext.QueryBuffer)),
                correlateSubqueryMethod,
                arguments);

            if (_queryCompilationContext.IsAsyncQuery)
            {
                var taskResultExpression = new TaskBlockingExpressionVisitor().Visit(result);

                return(taskResultExpression);
            }

            return(result);
        }
        public object CreateSecurityObject(IModel model, ISecurityObjectRepository securityObjectRepository)
        {
            Type targetType = RealObject.GetType();

            SecurityObject = Activator.CreateInstance(RealObject.GetType());
            IEntityType entityType = model.FindEntityType(targetType);
            IEnumerable <PropertyInfo> propertiesInfo = targetType.GetRuntimeProperties();
            IEnumerable <INavigation>  navigations    = entityType.GetNavigations();

            foreach (PropertyInfo propertyInfo in propertiesInfo)
            {
                object defaultValue = propertyInfo.GetValue(SecurityObject);
                defaultValueDictionary[propertyInfo.Name] = defaultValue;
                if (this.IsPropertyBlocked(propertyInfo.Name))
                {
                    if (navigations.Any(p => p.Name == propertyInfo.Name))
                    {
                        INavigation navigation = navigations.First(p => p.Name == propertyInfo.Name);
                        if (navigation.IsCollection())
                        {
                            if (propertyInfo.SetMethod != null)
                            {
                                propertyInfo.SetValue(SecurityObject, null);
                            }
                        }
                    }
                    continue;
                }
                if (navigations.Any(p => p.Name == propertyInfo.Name))
                {
                    INavigation navigation = navigations.First(p => p.Name == propertyInfo.Name);
                    if (navigation.IsCollection())
                    {
                        IClrCollectionAccessor collectionAccessor         = navigation.GetCollectionAccessor();
                        IEnumerable            objectRealListProperty     = (IEnumerable)propertyInfo.GetValue(RealObject);
                        IEnumerable            objectSecurityListProperty = (IEnumerable)propertyInfo.GetValue(SecurityObject);
                        List <object>          denyObject;
                        BlockedObjectsInListProperty.TryGetValue(propertyInfo.Name, out denyObject);
                        if (objectRealListProperty != null)
                        {
                            foreach (object objInList in objectRealListProperty)
                            {
                                if (denyObject != null && denyObject.Contains(objInList))
                                {
                                    continue;
                                }
                                object objectToAdd;
                                SecurityObjectBuilder metadata = securityObjectRepository.GetObjectMetaData(objInList);
                                if (metadata != null)
                                {
                                    if (metadata.SecurityObject != null)
                                    {
                                        objectToAdd = metadata.SecurityObject;
                                    }
                                    else
                                    {
                                        objectToAdd = metadata.CreateSecurityObject(model, securityObjectRepository);
                                    }
                                }
                                else
                                {
                                    throw new Exception();
                                }
                                collectionAccessor.Add(SecurityObject, objectToAdd);
                            }
                        }
                    }
                    else
                    {
                        object realValue = propertyInfo.GetValue(RealObject);
                        SecurityObjectBuilder metadata = securityObjectRepository.GetObjectMetaData(realValue);
                        if (metadata != null && realValue != null)
                        {
                            if (metadata.SecurityObject == null)
                            {
                                metadata.SecurityObject = metadata.CreateSecurityObject(model, securityObjectRepository);
                            }
                            if (propertyInfo.SetMethod != null)
                            {
                                propertyInfo.SetValue(SecurityObject, metadata.SecurityObject);
                            }
                        }
                        else
                        {
                            if (propertyInfo.SetMethod != null)
                            {
                                propertyInfo.SetValue(SecurityObject, realValue);
                            }
                        }
                    }
                }
                else
                {
                    if (propertyInfo.SetMethod != null)
                    {
                        object realValue = propertyInfo.GetValue(RealObject);
                        propertyInfo.SetValue(SecurityObject, realValue);
                    }
                }
            }
            foreach (PropertyInfo propertyInfo in propertiesInfo)
            {
                object originalValue = propertyInfo.GetValue(SecurityObject);
                originalValueSecurityObjectDictionary.Add(propertyInfo.Name, originalValue);
            }

            if (SecurityObject is ISecurityEntity)
            {
                ISecurityEntity securityEntity = (ISecurityEntity)SecurityObject;

                List <string> blockedMembers = new List <string>();
                blockedMembers.AddRange(BlockedProperties);
                blockedMembers.AddRange(BlockedNavigationProperties);

                securityEntity.BlockedMembers = blockedMembers;
            }

            return(SecurityObject);
        }
            private static void IncludeCollection <TEntity, TIncludedEntity>(
                QueryContext queryContext,
                DbDataReader dbDataReader,
                TEntity entity,
                Func <QueryContext, DbDataReader, object[]> outerKeySelector,
                Func <QueryContext, DbDataReader, object[]> innerKeySelector,
                Func <QueryContext, DbDataReader, ResultCoordinator, TIncludedEntity> innerShaper,
                INavigation navigation,
                INavigation inverseNavigation,
                Action <TEntity, TIncludedEntity> fixup,
                bool trackingQuery,
                ResultCoordinator resultCoordinator)
            {
                if (entity is null)
                {
                    return;
                }

                if (trackingQuery)
                {
                    queryContext.StateManager.TryGetEntry(entity).SetIsLoaded(navigation);
                }
                else
                {
                    SetIsLoadedNoTracking(entity, navigation);
                }

                var innerKey      = innerKeySelector(queryContext, dbDataReader);
                var outerKey      = outerKeySelector(queryContext, dbDataReader);
                var relatedEntity = innerShaper(queryContext, dbDataReader, resultCoordinator);

                if (ReferenceEquals(relatedEntity, null))
                {
                    navigation.GetCollectionAccessor().GetOrCreate(entity);
                    return;
                }

                if (!trackingQuery)
                {
                    fixup(entity, relatedEntity);
                    if (inverseNavigation != null && !inverseNavigation.IsCollection())
                    {
                        SetIsLoadedNoTracking(relatedEntity, inverseNavigation);
                    }
                }

                var hasNext = resultCoordinator.HasNext ?? dbDataReader.Read();

                while (hasNext)
                {
                    resultCoordinator.HasNext = null;
                    var currentOuterKey = outerKeySelector(queryContext, dbDataReader);
                    if (!StructuralComparisons.StructuralEqualityComparer.Equals(outerKey, currentOuterKey))
                    {
                        resultCoordinator.HasNext = true;
                        break;
                    }

                    var currentInnerKey = innerKeySelector(queryContext, dbDataReader);
                    if (StructuralComparisons.StructuralEqualityComparer.Equals(innerKey, currentInnerKey))
                    {
                        continue;
                    }

                    relatedEntity = innerShaper(queryContext, dbDataReader, resultCoordinator);
                    if (!trackingQuery)
                    {
                        fixup(entity, relatedEntity);
                        if (inverseNavigation != null && !inverseNavigation.IsCollection())
                        {
                            SetIsLoadedNoTracking(relatedEntity, inverseNavigation);
                        }
                    }

                    hasNext = resultCoordinator.HasNext ?? dbDataReader.Read();
                }

                resultCoordinator.HasNext = hasNext;
            }
Пример #21
0
        private void Unfixup(INavigation navigation, InternalEntityEntry oldPrincipalEntry, InternalEntityEntry dependentEntry)
        {
            if (navigation.IsDependentToPrincipal())
            {
                navigation.GetSetter().SetClrValue(dependentEntry.Entity, null);

                dependentEntry.RelationshipsSnapshot.TakeSnapshot(navigation);
            }
            else
            {
                if (navigation.IsCollection())
                {
                    var collectionAccessor = navigation.GetCollectionAccessor();
                    if (collectionAccessor.Contains(oldPrincipalEntry.Entity, dependentEntry.Entity))
                    {
                        collectionAccessor.Remove(oldPrincipalEntry.Entity, dependentEntry.Entity);
                    }
                }
                else
                {
                    navigation.GetSetter().SetClrValue(oldPrincipalEntry.Entity, null);
                }
            }
        }