Ejemplo n.º 1
0
        private static Type GetNamedPropertyType(NamedPropertyExpression property, IList <Expression> expressions)
        {
            Type namedPropertyGenericType;

            if (property.NullCheck != null)
            {
                namedPropertyGenericType = SingleExpandedPropertyTypes[expressions.Count];
            }
            else if (property.PageSize != null || property.CountOption != null)
            {
                namedPropertyGenericType = CollectionExpandedPropertyTypes[expressions.Count];
            }
            else if (property.AutoSelected)
            {
                namedPropertyGenericType = AutoSelectedNamedPropertyTypes[expressions.Count];
            }
            else
            {
                namedPropertyGenericType = NamedPropertyTypes[expressions.Count];
            }

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

            return(namedPropertyGenericType.MakeGenericType(elementType));
        }
Ejemplo n.º 2
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)
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Value"), property.Value));
            }
            else
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Collection"), property.Value));
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("PageSize"), Expression.Constant(property.PageSize)));
            }

            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));
        }
Ejemplo n.º 3
0
        private Expression BuildPropertyContainer(IEdmEntityType elementType, Expression source,
                                                  Dictionary <IEdmNavigationProperty, ExpandedNavigationSelectItem> propertiesToExpand,
                                                  ISet <IEdmStructuralProperty> propertiesToInclude, ISet <IEdmStructuralProperty> autoSelectedProperties)
        {
            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 = Expression.Equal(propertyValue, Expression.Constant(null));

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

                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;
                    }
                }

                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
                });
            }

            // create a property container that holds all these property names and values.
            return(PropertyContainer.CreatePropertyContainer(includedProperties));
        }
Ejemplo n.º 4
0
        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
            {
                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));
        }
Ejemplo n.º 5
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));
        }
Ejemplo n.º 6
0
        public void CreatePropertyContainer_WithNullPropertyName_DoesntIncludeTheProperty()
        {
            // Arrange
            Expression propertyName          = Expression.Constant(null, typeof(string));
            Expression propertyValue         = Expression.Constant(new TestEntity());
            NamedPropertyExpression property = new NamedPropertyExpression(propertyName, propertyValue);
            var properties = new[] { property, property };

            // Act
            Expression containerExpression = PropertyContainer.CreatePropertyContainer(properties);

            // Assert
            PropertyContainer container = ToContainer(containerExpression);

            Assert.Empty(container.ToDictionary(new IdentityPropertyMapper(), includeAutoSelected: true));
        }
Ejemplo n.º 7
0
        public void ToDictionary_Throws_IfMappingFunctionReturns_NullOrEmpty(string mappedName)
        {
            // Arrange
            IList <NamedPropertyExpression> properties = new NamedPropertyExpression[]
            {
                new NamedPropertyExpression(name: Expression.Constant("PropA"), value: Expression.Constant(3))
            };
            Expression        containerExpression = PropertyContainer.CreatePropertyContainer(properties);
            PropertyContainer container           = ToContainer(containerExpression);

            Mock <IPropertyMapper> mapperMock = new Mock <IPropertyMapper>();

            mapperMock.Setup(m => m.MapProperty("PropA")).Returns(mappedName);

            // Act & Assert
            Assert.Throws <InvalidOperationException>(() =>
                                                      container.ToDictionary(mapperMock.Object), "The key mapping for the property 'PropA' can't be null or empty.");
        }
Ejemplo n.º 8
0
        // Expression:
        // new NamedProperty<T> { Name = property.Name, Value = property.Value, Next0 = next0, Next1 = next1, .... }.
        private static Expression CreateNamedPropertyCreationExpression(NamedPropertyExpression property, IList <Expression> expressions)
        {
            Contract.Assert(property != null);
            Contract.Assert(property.Value != null);

            Type namedPropertyType = GetNamedPropertyType(property, expressions);
            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));
            }

            for (int i = 0; i < expressions.Count; i++)
            {
                memberBindings.Add(Expression.Bind(namedPropertyType.GetProperty("Next" + i), expressions[i]));
            }

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

            return(Expression.MemberInit(Expression.New(namedPropertyType), memberBindings));
        }
Ejemplo n.º 9
0
        // Expression:
        //      new NamedProperty<T>
        //      {
        //          Name = properties[0].Key,
        //          Value = properties[0].Value,
        //
        //          Next0 = new NamedProperty<> { ..... }
        //          Next1 = new NamedProperty<> { ..... },
        //          ...
        //      }
        public static Expression CreatePropertyContainer(IList <NamedPropertyExpression> properties)
        {
            Expression container = null;

            // build the linked list of properties.
            if (properties.Count >= 1)
            {
                NamedPropertyExpression property = properties.First();
                int count = properties.Count - 1;
                List <Expression> nextExpressions = new List <Expression>();
                int parts  = SingleExpandedPropertyTypes.Count - 1;
                int offset = 0;
                for (int step = parts; step > 0; step--)
                {
                    int leftSize = GetLeftSize(count - offset, step);
                    nextExpressions.Add(CreatePropertyContainer(properties.Skip(1 + offset).Take(leftSize).ToList()));
                    offset += leftSize;
                }

                container = CreateNamedPropertyCreationExpression(property, nextExpressions.Where(e => e != null).ToList());
            }

            return(container);
        }
Ejemplo n.º 10
0
        public void ToDictionary_AppliesMappingToAllProperties()
        {
            // Arrange
            IList <NamedPropertyExpression> properties = new NamedPropertyExpression[]
            {
                new NamedPropertyExpression(name: Expression.Constant("PropA"), value: Expression.Constant(3)),
                new NamedPropertyExpression(name: Expression.Constant("PropB"), value: Expression.Constant(6))
            };
            Expression        containerExpression = PropertyContainer.CreatePropertyContainer(properties);
            PropertyContainer container           = ToContainer(containerExpression);

            Mock <IPropertyMapper> mapperMock = new Mock <IPropertyMapper>();

            mapperMock.Setup(m => m.MapProperty("PropA")).Returns("PropertyA");
            mapperMock.Setup(m => m.MapProperty("PropB")).Returns("PropB");

            //Act
            IDictionary <string, object> result = container.ToDictionary(mapperMock.Object);

            //Assert
            Assert.NotNull(result);
            Assert.True(result.ContainsKey("PropertyA"));
            Assert.True(result.ContainsKey("PropB"));
        }
Ejemplo n.º 11
0
        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 = Expression.Equal(propertyValue, Expression.Constant(null));

                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);
                }

                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));
        }
        public void ToDictionary_Throws_IfMappingFunctionReturns_NullOrEmpty(string mappedName)
        {
            // Arrange
            IList<NamedPropertyExpression> properties = new NamedPropertyExpression[]
            {
                new NamedPropertyExpression(name: Expression.Constant("PropA"), value: Expression.Constant(3))
            };
            Expression containerExpression = PropertyContainer.CreatePropertyContainer(properties);
            PropertyContainer container = ToContainer(containerExpression);

            Mock<IPropertyMapper> mapperMock = new Mock<IPropertyMapper>();
            mapperMock.Setup(m => m.MapProperty("PropA")).Returns(mappedName);

            // Act & Assert
            Assert.Throws<InvalidOperationException>(() =>
                container.ToDictionary(mapperMock.Object), "The key mapping for the property 'PropA' can't be null or empty.");
        }
        public void ToDictionary_AppliesMappingToAllProperties()
        {
            // Arrange
            IList<NamedPropertyExpression> properties = new NamedPropertyExpression[]
            {
                new NamedPropertyExpression(name: Expression.Constant("PropA"), value: Expression.Constant(3)),
                new NamedPropertyExpression(name: Expression.Constant("PropB"), value: Expression.Constant(6))
            };
            Expression containerExpression = PropertyContainer.CreatePropertyContainer(properties);
            PropertyContainer container = ToContainer(containerExpression);

            Mock<IPropertyMapper> mapperMock = new Mock<IPropertyMapper>();
            mapperMock.Setup(m => m.MapProperty("PropA")).Returns("PropertyA");
            mapperMock.Setup(m => m.MapProperty("PropB")).Returns("PropB");

            //Act
            IDictionary<string, object> result = container.ToDictionary(mapperMock.Object);

            //Assert
            Assert.NotNull(result);
            Assert.True(result.ContainsKey("PropertyA"));
            Assert.True(result.ContainsKey("PropB"));
        }
        public void CreatePropertyContainer_WithNullPropertyName_DoesntIncludeTheProperty()
        {
            // Arrange
            Expression propertyName = Expression.Constant(null, typeof(string));
            Expression propertyValue = Expression.Constant(new TestEntity());
            NamedPropertyExpression property = new NamedPropertyExpression(propertyName, propertyValue);
            var properties = new[] { property, property };

            // Act
            Expression containerExpression = PropertyContainer.CreatePropertyContainer(properties);

            // Assert
            PropertyContainer container = ToContainer(containerExpression);
            Assert.Empty(container.ToDictionary(new IdentityPropertyMapper(), includeAutoSelected: true));
        }
Ejemplo n.º 15
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.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.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 begining 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; // 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;
                this._elementType     = wrapperType;
            }

            return(query);
        }