コード例 #1
0
        // Expression:
        // new NamedProperty<T> { Name = property.Name, Value = property.Value, Next = next }.
        private static Expression CreateNamedPropertyCreationExpression(NamedPropertyExpression property, Expression next)
        {
            Contract.Assert(property != null);
            Contract.Assert(property.Value != null);

            Type namedPropertyType = GetNamedPropertyType(property, next);
            List <MemberBinding> memberBindings = new List <MemberBinding>();

            memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Name"), property.Name));

            var collectionProperty = namedPropertyType.GetProperty("Collection");

            if ((property.PageSize != null || property.CountOption != null) && collectionProperty != null)
            {
                if (!property.OnlyCount.HasValue || property.OnlyCount == false)
                {
                    memberBindings.Add(Expression.Bind(collectionProperty, property.Value));
                }

                if (property.PageSize != null)
                {
                    memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("PageSize"),
                                                       Expression.Constant(property.PageSize)));
                }

                if (property.CountOption != null && property.CountOption.Value)
                {
                    memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("TotalCount"), property.TotalCount));
                }

                if (property.OnlyCount.HasValue)
                {
                    var onlyCountProperty = namedPropertyType.GetProperty("OnlyCount");
                    if (onlyCountProperty != null)
                    {
                        memberBindings.Add(Expression.Bind(onlyCountProperty, Expression.Constant(property.OnlyCount)));
                    }
                }
            }
            else
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty(nameof(NamedProperty <object> .RelationshipValue)), property.Value));
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty(nameof(NamedProperty <object> .ValueProperty)), Expression.Constant(nameof(NamedProperty <object> .RelationshipValue))));
            }

            if (next != null)
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Next"), next));
            }
            if (property.NullCheck != null)
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("IsNull"), property.NullCheck));
            }

            var newExpression = Expression.New(namedPropertyType);
            var namedPropertyCreationExpression = Expression.MemberInit(newExpression, memberBindings);

            return(namedPropertyCreationExpression);
        }
コード例 #2
0
        private static Type GetNamedPropertyType(NamedPropertyExpression property, Expression next)
        {
            Type namedPropertyGenericType;

            if (next == null)
            {
                if (property.NullCheck != null)
                {
                    namedPropertyGenericType = typeof(SingleExpandedProperty <>);
                }
                else if (property.PageSize != null || property.CountOption != null)
                {
                    namedPropertyGenericType = typeof(CollectionExpandedProperty <>);
                }
                else if (property.AutoSelected)
                {
                    namedPropertyGenericType = typeof(AutoSelectedNamedProperty <>);
                }
                else
                {
                    namedPropertyGenericType = typeof(NamedProperty <>);
                }
            }
            else
            {
                if (property.NullCheck != null)
                {
                    namedPropertyGenericType = typeof(SingleExpandedPropertyWithNext <>);
                }
                else if (property.PageSize != null || property.CountOption != null)
                {
                    namedPropertyGenericType = typeof(CollectionExpandedPropertyWithNext <>);
                }
                else if (property.AutoSelected)
                {
                    namedPropertyGenericType = typeof(AutoSelectedNamedPropertyWithNext <>);
                }
                else
                {
                    namedPropertyGenericType = typeof(NamedPropertyWithNext <>);
                }
            }

            Type elementType = (property.PageSize == null && property.CountOption == null)
                ? property.Value.Type
                : property.Value.Type.GetInnerElementType();

            return(namedPropertyGenericType.MakeGenericType(elementType));
        }
コード例 #3
0
        // Expression:
        // new NamedProperty<T> { Name = property.Name, Value = property.Value, Next = next }.
        private static Expression CreateNamedPropertyCreationExpression(NamedPropertyExpression property, Expression next)
        {
            Contract.Assert(property != null);
            Contract.Assert(property.Value != null);

            Type namedPropertyType = GetNamedPropertyType(property, next);
            List <MemberBinding> memberBindings = new List <MemberBinding>();

            memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Name"), property.Name));

            if (property.PageSize != null || property.CountOption != null)
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Collection"), property.Value));

                if (property.PageSize != null)
                {
                    memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("PageSize"),
                                                       Expression.Constant(property.PageSize)));
                }

                if (property.CountOption != null && property.CountOption.Value)
                {
                    memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("TotalCount"), property.TotalCount));
                }
            }
            else
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Value"), property.Value));
            }

            if (next != null)
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Next"), next));
            }
            if (property.NullCheck != null)
            {
                // Microsoft.EntityFrameworkCore.Query.Internal
                // provider cannot handle the null check, resulting
                // in a "must be reducible node" error, so null
                // checking has been moved locally into the IsNull
                // property
                //memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("IsNull"), property.NullCheck));
            }

            return(Expression.MemberInit(Expression.New(namedPropertyType), memberBindings));
        }
コード例 #4
0
        // Expression:
        // new NamedProperty<T> { Name = property.Name, Value = property.Value, Next = next }.
        private static Expression CreateNamedPropertyCreationExpression(NamedPropertyExpression property, Expression next)
        {
            Contract.Assert(property != null);
            Contract.Assert(property.Value != null);

            Type namedPropertyType = GetNamedPropertyType(property, next);
            List <MemberBinding> memberBindings = new List <MemberBinding>();

            memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Name"), property.Name));

            if (property.PageSize != null || property.CountOption != null)
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Collection"), property.Value));

                if (property.PageSize != null)
                {
                    memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("PageSize"),
                                                       Expression.Constant(property.PageSize)));
                }

                if (property.CountOption != null && property.CountOption.Value)
                {
                    memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("TotalCount"), property.TotalCount));
                }
            }
            else
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Value"), property.Value));
            }

            if (next != null)
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Next"), next));
            }
            if (property.NullCheck != null)
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("IsNull"), property.NullCheck));
            }

            return(Expression.MemberInit(Expression.New(namedPropertyType), memberBindings));
        }
        private static Expression CreateNextNamedPropertyCreationExpression(NamedPropertyExpression property, Expression next)
        {
            Contract.Assert(property != null);
            Contract.Assert(property.Value != null);

            Type namedPropertyType = null;

            if (next != null)
            {
                if (property.Value.Type == typeof(GroupByWrapper))
                {
                    namedPropertyType = typeof(NestedProperty);
                }
                else
                {
                    namedPropertyType = typeof(AggregationPropertyContainer);
                }
            }
            else
            {
                if (property.Value.Type == typeof(GroupByWrapper))
                {
                    namedPropertyType = typeof(NestedPropertyLastInChain);
                }
                else
                {
                    namedPropertyType = typeof(LastInChain);
                }
            }

            List <MemberBinding> memberBindings = new List <MemberBinding>();

            memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Name"), property.Name));

            if (property.Value.Type == typeof(GroupByWrapper))
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("NestedValue"), property.Value));
            }
            else
            {
                string prop = null;
                if (property.Value.Type == typeof(int))
                {
                    prop = nameof(IntValue);
                }
                else if (property.Value.Type == typeof(short))
                {
                    prop = nameof(ShortValue);
                }
                else if (property.Value.Type == typeof(long))
                {
                    prop = nameof(LongValue);
                }
                else if (property.Value.Type == typeof(decimal))
                {
                    prop = nameof(DecimalValue);
                }
                else if (property.Value.Type == typeof(string))
                {
                    prop = nameof(StringValue);
                }
                else if (property.Value.Type == typeof(bool))
                {
                    prop = nameof(BooleanValue);
                }
                else if (property.Value.Type == typeof(DateTime))
                {
                    prop = nameof(DateTimeValue);
                }
                else if (property.Value.Type == typeof(DateTimeOffset))
                {
                    prop = nameof(DateTimeOffsetValue);
                }
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("ValueProperty"), Expression.Constant(prop)));
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty(prop), Expression.Convert(property.Value, property.Value.Type)));
                //memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Other"), property.Value));
            }

            if (next != null)
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Next"), next));
            }

            if (property.NullCheck != null)
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("IsNull"), property.NullCheck));
            }

            return(Expression.MemberInit(Expression.New(namedPropertyType), memberBindings));
        }
コード例 #6
0
        /// <summary>
        /// Pre flattens properties referenced in aggregate clause to avoid generation of nested queries by EF.
        /// For query like groupby((A), aggregate(B/C with max as Alias1, B/D with max as Alias2)) we need to generate
        /// .Select(
        ///     $it => new FlattenninWrapper () {
        ///         Source = $it, // Will used in groupby stage
        ///         Container = new {
        ///             Value = $it.B.C
        ///             Next = new {
        ///                 Value = $it.B.D
        ///             }
        ///         }
        ///     }
        /// )
        /// Also we need to populate expressions to access B/C and B/D in aggregate stage. It will look like:
        /// B/C : $it.Container.Value
        /// B/D : $it.Container.Next.Value
        /// </summary>
        /// <param name="query"></param>
        /// <returns>Query with Select that flattens properties</returns>
        private IQueryable FlattenReferencedProperties(IQueryable query)
        {
            if (_aggregateExpressions != null &&
                _aggregateExpressions.OfType <AggregateExpression>().Any(e => e.Method != AggregationMethod.VirtualPropertyCount) &&
                _groupingProperties != null &&
                _groupingProperties.Any() &&
                (FlattenedPropertyContainer == null || !FlattenedPropertyContainer.Any()))
            {
                var wrapperType             = typeof(FlatteningWrapper <>).MakeGenericType(this.ElementType);
                var sourceProperty          = wrapperType.GetProperty("Source");
                List <MemberAssignment> wta = new List <MemberAssignment>();
                wta.Add(Expression.Bind(sourceProperty, this.LambdaParameter));

                var aggrregatedPropertiesToFlatten = _aggregateExpressions.OfType <AggregateExpression>().Where(e => e.Method != AggregationMethod.VirtualPropertyCount).ToList();
                // Generated Select will be stack like, meaning that first property in the list will be deepest one
                // For example if we add $it.B.C, $it.B.D, select will look like
                // new {
                //      Value = $it.B.C
                //      Next = new {
                //          Value = $it.B.D
                //      }
                // }
                // We are generated references (in currentContainerExpression) from  the beginning of the  Select ($it.Value, then $it.Next.Value etc.)
                // We have proper match we need insert properties in reverse order
                // After this
                // properties = { $it.B.D, $it.B.C}
                // _preFlattendMAp = { {$it.B.C, $it.Value}, {$it.B.D, $it.Next.Value} }
                var properties = new NamedPropertyExpression[aggrregatedPropertiesToFlatten.Count];
                var aliasIdx   = aggrregatedPropertiesToFlatten.Count - 1;
                var aggParam   = Expression.Parameter(wrapperType, "$it");
                var currentContainerExpression = Expression.Property(aggParam, GroupByContainerProperty);
                foreach (var aggExpression in aggrregatedPropertiesToFlatten)
                {
                    var alias = "Property" + aliasIdx.ToString(CultureInfo.CurrentCulture); // We just need unique alias, we aren't going to use it

                    // Add Value = $it.B.C
                    var propAccessExpression = BindAccessor(aggExpression.Expression);
                    var type = propAccessExpression.Type;
                    propAccessExpression = WrapConvert(propAccessExpression);
                    properties[aliasIdx] = new NamedPropertyExpression(Expression.Constant(alias), propAccessExpression);

                    // Save $it.Container.Next.Value for future use
                    UnaryExpression flatAccessExpression = Expression.Convert(
                        Expression.Property(currentContainerExpression, "Value"),
                        type);
                    currentContainerExpression = Expression.Property(currentContainerExpression, "Next");
                    _preFlattenedMap.Add(aggExpression.Expression, flatAccessExpression);
                    aliasIdx--;
                }

                var wrapperProperty = ResultClrType.GetProperty(GroupByContainerProperty);

                wta.Add(Expression.Bind(wrapperProperty, AggregationPropertyContainer.CreateNextNamedPropertyContainer(properties)));

                var flatLambda = Expression.Lambda(Expression.MemberInit(Expression.New(wrapperType), wta), LambdaParameter);

                query = ExpressionHelpers.Select(query, flatLambda, this.ElementType);

                // We applied flattening let .GroupBy know about it.
                this.LambdaParameter = aggParam;
            }

            return(query);
        }
コード例 #7
0
ファイル: SelectExpandBinder.cs プロジェクト: akorchev/odata
        private Expression BuildPropertyContainer(IEdmEntityType elementType, Expression source,
                                                  Dictionary <IEdmNavigationProperty, ExpandedNavigationSelectItem> propertiesToExpand,
                                                  ISet <IEdmStructuralProperty> propertiesToInclude, ISet <IEdmStructuralProperty> autoSelectedProperties, bool isSelectingOpenTypeSegments)
        {
            IList <NamedPropertyExpression> includedProperties = new List <NamedPropertyExpression>();

            foreach (KeyValuePair <IEdmNavigationProperty, ExpandedNavigationSelectItem> kvp in propertiesToExpand)
            {
                IEdmNavigationProperty       propertyToExpand = kvp.Key;
                ExpandedNavigationSelectItem expandItem       = kvp.Value;
                SelectExpandClause           projection       = expandItem.SelectAndExpand;

                Expression propertyName  = CreatePropertyNameExpression(elementType, propertyToExpand, source);
                Expression propertyValue = CreatePropertyValueExpressionWithFilter(elementType, propertyToExpand, source,
                                                                                   expandItem.FilterOption);
                Expression nullCheck = GetNullCheckExpression(propertyToExpand, propertyValue, projection);

                Expression countExpression = CreateTotalCountExpression(propertyValue, expandItem);

                // projection can be null if the expanded navigation property is not further projected or expanded.
                if (projection != null)
                {
                    propertyValue = ProjectAsWrapper(propertyValue, projection, propertyToExpand.ToEntityType(), expandItem.NavigationSource as IEdmEntitySet,
                                                     expandItem);
                }

                NamedPropertyExpression propertyExpression = new NamedPropertyExpression(propertyName, propertyValue);
                if (projection != null)
                {
                    if (!propertyToExpand.Type.IsCollection())
                    {
                        propertyExpression.NullCheck = nullCheck;
                    }
                    else if (_settings.PageSize != null)
                    {
                        propertyExpression.PageSize = _settings.PageSize.Value;
                    }
                    propertyExpression.TotalCount  = countExpression;
                    propertyExpression.CountOption = expandItem.CountOption;
                }

                includedProperties.Add(propertyExpression);
            }

            foreach (IEdmStructuralProperty propertyToInclude in propertiesToInclude)
            {
                Expression propertyName  = CreatePropertyNameExpression(elementType, propertyToInclude, source);
                Expression propertyValue = CreatePropertyValueExpression(elementType, propertyToInclude, source);
                includedProperties.Add(new NamedPropertyExpression(propertyName, propertyValue));
            }

            foreach (IEdmStructuralProperty propertyToInclude in autoSelectedProperties)
            {
                Expression propertyName  = CreatePropertyNameExpression(elementType, propertyToInclude, source);
                Expression propertyValue = CreatePropertyValueExpression(elementType, propertyToInclude, source);
                includedProperties.Add(new NamedPropertyExpression(propertyName, propertyValue)
                {
                    AutoSelected = true
                });
            }

            if (isSelectingOpenTypeSegments)
            {
                var dynamicPropertyDictionary = EdmLibHelpers.GetDynamicPropertyDictionary(elementType, _model);

                Expression propertyName          = Expression.Constant(dynamicPropertyDictionary.Name);
                Expression propertyValue         = Expression.Property(source, dynamicPropertyDictionary.Name);
                Expression nullablePropertyValue = ExpressionHelpers.ToNullable(propertyValue);
                if (_settings.HandleNullPropagation == HandleNullPropagationOption.True)
                {
                    // source == null ? null : propertyValue
                    propertyValue = Expression.Condition(
                        test: Expression.Equal(source, Expression.Constant(value: null)),
                        ifTrue: Expression.Constant(value: null, type: propertyValue.Type.ToNullable()),
                        ifFalse: nullablePropertyValue);
                }
                else
                {
                    propertyValue = nullablePropertyValue;
                }

                includedProperties.Add(new NamedPropertyExpression(propertyName, propertyValue));
            }

            // create a property container that holds all these property names and values.
            return(PropertyContainer.CreatePropertyContainer(includedProperties));
        }