예제 #1
0
        public Expression BuildSelect(SelectExpandClause selectClause, Expression source, bool navigationNextLink, bool skipToken)
        {
            foreach (SelectItem selectItemClause in selectClause.SelectedItems)
            {
                var          selectItemTranslator = new OeSelectItemTranslator(_navigationItem, navigationNextLink, source, _joinBuilder, skipToken);
                OeSelectItem selectItem           = selectItemClause.TranslateWith(selectItemTranslator);
                if (selectItem != null)
                {
                    if (selectItem.EdmProperty is IEdmNavigationProperty)
                    {
                        source = selectItemTranslator.Source;
                    }
                    else
                    {
                        _navigationItem.AddSelectItem(selectItem);
                    }
                }
            }

            if (_navigationItem.SelectItems.Count > 0)
            {
                AddKey(_metadataLevel != OeMetadataLevel.Full);
            }

            return(source);
        }
예제 #2
0
 internal OeSelectTranslator(OeJoinBuilder joinBuilder, OeSelectItem navigationItem)
 {
     _joinBuilder    = joinBuilder;
     _navigationItem = navigationItem;
     _visitor        = joinBuilder.Visitor;
     _metadataLevel  = OeMetadataLevel.None;
 }
예제 #3
0
        private static OeEntryFactory CreateEntryFactory(IEdmModel edmModel, OeSelectItem root, Type clrType)
        {
            ParameterExpression parameter      = Expression.Parameter(typeof(Object));
            UnaryExpression     typedParameter = Expression.Convert(parameter, clrType);

            if (root.HasNavigationItems)
            {
                List <OeSelectItem> navigationItems = FlattenNavigationItems(root, false);
                IReadOnlyList <MemberExpression> navigationProperties = OeExpressionHelper.GetPropertyExpressions(typedParameter);

                for (int i = navigationItems.Count - 1; i >= 0; i--)
                {
                    OeSelectItem     navigationItem        = navigationItems[i];
                    OeEntryFactory[] nestedNavigationLinks = GetNestedNavigationLinks(navigationItem);

                    OeEntryFactory       entryFactory;
                    Type                 clrEntityType = edmModel.GetClrType(navigationItem.EntitySet);
                    OePropertyAccessor[] accessors     = GetAccessors(navigationProperties[i].Type, navigationItem.EntitySet, navigationItem.SelectItems);
                    LambdaExpression     linkAccessor  = Expression.Lambda(navigationProperties[i], parameter);
                    if (i == 0)
                    {
                        entryFactory = OeEntryFactory.CreateEntryFactoryParent(clrEntityType, navigationItem.EntitySet, accessors, nestedNavigationLinks, linkAccessor);
                    }
                    else
                    {
                        var resourceInfo = new ODataNestedResourceInfo()
                        {
                            IsCollection = navigationItem.EdmProperty.Type.Definition is EdmCollectionType,
                            Name         = navigationItem.EdmProperty.Name
                        };
                        entryFactory             = OeEntryFactory.CreateEntryFactoryNested(clrEntityType, navigationItem.EntitySet, accessors, nestedNavigationLinks, linkAccessor, resourceInfo);
                        entryFactory.CountOption = navigationItem.ExpandedNavigationSelectItem.CountOption;
                    }
                    navigationItem.EntryFactory = entryFactory;
                }
            }
            else
            {
                IReadOnlyList <MemberExpression> propertyExpressions = OeExpressionHelper.GetPropertyExpressions(typedParameter);
                OePropertyAccessor[]             accessors;
                if (root.SelectItems.Count == 0)
                {
                    accessors = OePropertyAccessor.CreateFromType(typedParameter.Type, root.EntitySet);
                }
                else
                {
                    var accessorList = new List <OePropertyAccessor>(root.SelectItems.Count);
                    for (int i = 0; i < root.SelectItems.Count; i++)
                    {
                        OeSelectItem selectItem = root.SelectItems[i];
                        accessorList.Add(OePropertyAccessor.CreatePropertyAccessor(selectItem.EdmProperty, propertyExpressions[i], parameter, selectItem.SkipToken));
                    }
                    accessors = accessorList.ToArray();
                }
                Type clrEntityType = edmModel.GetClrType(root.EntitySet);
                root.EntryFactory = OeEntryFactory.CreateEntryFactory(clrEntityType, root.EntitySet, accessors);
            }

            return(root.EntryFactory);
        }
예제 #4
0
        private static Expression BuildOrderBySkipToken(OeSelectItem navigationItem, OrderByClause orderByClause, Expression source, OeJoinBuilder joinBuilder, bool hasSelectItems)
        {
            while (orderByClause != null)
            {
                var propertyNode = (SingleValuePropertyAccessNode)orderByClause.Expression;
                if (propertyNode.Source is SingleNavigationNode navigationNode)
                {
                    OeSelectItem match = null;
                    ExpandedNavigationSelectItem navigationSelectItem = null;
                    do
                    {
                        if ((match = navigationItem.FindHierarchyNavigationItem(navigationNode.NavigationProperty)) != null)
                        {
                            match.AddSelectItem(new OeSelectItem(propertyNode.Property, true));
                            break;
                        }

                        SelectExpandClause selectExpandClause;
                        if (navigationSelectItem == null)
                        {
                            var pathSelectItem = new PathSelectItem(new ODataSelectPath(new PropertySegment((IEdmStructuralProperty)propertyNode.Property)));
                            selectExpandClause = new SelectExpandClause(new[] { pathSelectItem }, false);
                        }
                        else
                        {
                            selectExpandClause = new SelectExpandClause(new[] { navigationSelectItem }, false);
                        }

                        var segment = new NavigationPropertySegment(navigationNode.NavigationProperty, navigationNode.NavigationSource);
                        navigationSelectItem = new ExpandedNavigationSelectItem(new ODataExpandPath(segment), navigationNode.NavigationSource, selectExpandClause);
                    }while ((navigationNode = navigationNode.Source as SingleNavigationNode) != null);

                    if (navigationSelectItem != null)
                    {
                        if (match == null)
                        {
                            match = navigationItem;
                        }

                        var selectItemTranslator = new OeSelectItemTranslator(match, false, source, joinBuilder, true);
                        navigationSelectItem.TranslateWith(selectItemTranslator);
                        source = selectItemTranslator.Source;
                    }
                }
                else
                {
                    if (hasSelectItems)
                    {
                        navigationItem.AddSelectItem(new OeSelectItem(propertyNode.Property, true));
                    }
                }

                orderByClause = orderByClause.ThenBy;
            }

            return(source);
        }
예제 #5
0
        public IReadOnlyList <IEdmNavigationProperty> GetJoinPath()
        {
            var joinPath = new List <IEdmNavigationProperty>();

            for (OeSelectItem navigationItem = this; navigationItem.Parent != null; navigationItem = navigationItem.Parent)
            {
                joinPath.Insert(0, (IEdmNavigationProperty)navigationItem.EdmProperty);
            }
            return(joinPath);
        }
예제 #6
0
        private static OeEntryFactory[] GetNestedNavigationLinks(OeSelectItem navigationItem)
        {
            var nestedEntryFactories = new List <OeEntryFactory>(navigationItem.NavigationItems.Count);

            for (int i = 0; i < navigationItem.NavigationItems.Count; i++)
            {
                if (!navigationItem.NavigationItems[i].SkipToken)
                {
                    nestedEntryFactories.Add(navigationItem.NavigationItems[i].EntryFactory);
                }
            }
            return(nestedEntryFactories.ToArray());
        }
예제 #7
0
        public OeSelectItem(IEdmModel edmModel, OeSelectItem parent, ExpandedNavigationSelectItem expandedNavigationSelectItem, bool skipToken) : this()
        {
            var segment = (NavigationPropertySegment)expandedNavigationSelectItem.PathToNavigationProperty.LastSegment;

            var segments = new List <ODataPathSegment>(parent.Path);

            segments.AddRange(expandedNavigationSelectItem.PathToNavigationProperty);

            EdmProperty = segment.NavigationProperty;
            EntitySet   = (IEdmEntitySetBase)expandedNavigationSelectItem.NavigationSource ?? OeEdmClrHelper.GetEntitySet(edmModel, segment.NavigationProperty);
            ExpandedNavigationSelectItem = expandedNavigationSelectItem;
            Parent    = parent;
            Path      = new ODataPath(segments);
            SkipToken = skipToken;
        }
예제 #8
0
        public bool AddSelectItem(OeSelectItem selectItem)
        {
            int existsSelectItemIndex;

            if ((existsSelectItemIndex = FindSelectItem(selectItem.EdmProperty)) != -1)
            {
                if (_selectItems[existsSelectItemIndex].SkipToken && !selectItem.SkipToken)
                {
                    _selectItems[existsSelectItemIndex] = selectItem;
                }
                return(false);
            }

            _selectItems.Add(selectItem);
            return(true);
        }
예제 #9
0
        public OeSelectItem FindHierarchyNavigationItem(IEdmNavigationProperty navigationProperty)
        {
            if (EdmProperty == navigationProperty)
            {
                return(this);
            }

            for (int i = 0; i < _navigationItems.Count; i++)
            {
                OeSelectItem matched = _navigationItems[i].FindHierarchyNavigationItem(navigationProperty);
                if (matched != null)
                {
                    return(matched);
                }
            }

            return(null);
        }
예제 #10
0
        private static List <OeSelectItem> FlattenNavigationItems(OeSelectItem root, bool skipToken)
        {
            var navigationItems = new List <OeSelectItem>();
            var stack           = new Stack <ValueTuple <OeSelectItem, int> >();

            stack.Push(new ValueTuple <OeSelectItem, int>(root, 0));
            do
            {
                ValueTuple <OeSelectItem, int> stackItem = stack.Pop();
                if (stackItem.Item2 == 0 && (!stackItem.Item1.SkipToken || skipToken))
                {
                    navigationItems.Add(stackItem.Item1);
                }

                if (stackItem.Item2 < stackItem.Item1.NavigationItems.Count)
                {
                    stack.Push(new ValueTuple <OeSelectItem, int>(stackItem.Item1, stackItem.Item2 + 1));
                    OeSelectItem selectItem = stackItem.Item1.NavigationItems[stackItem.Item2];
                    stack.Push(new ValueTuple <OeSelectItem, int>(selectItem, 0));
                }
            }while (stack.Count > 0);
            return(navigationItems);
        }
예제 #11
0
 public void AddNavigationItem(OeSelectItem navigationItem)
 {
     _navigationItems.Add(navigationItem);
 }
예제 #12
0
 internal OeSelectTranslator(OeJoinBuilder joinBuilder, OeSelectItem navigationItem)
 {
     _joinBuilder    = joinBuilder;
     _navigationItem = navigationItem;
     _visitor        = joinBuilder.Visitor;
 }
예제 #13
0
        private static Expression SelectStructuralProperties(Expression source, OeSelectItem root)
        {
            if (!root.HasNavigationItems)
            {
                return(source);
            }

            ParameterExpression parameter          = Expression.Parameter(OeExpressionHelper.GetCollectionItemType(source.Type));
            IReadOnlyList <MemberExpression> joins = OeExpressionHelper.GetPropertyExpressions(parameter);
            var newJoins = new Expression[joins.Count];

            List <OeSelectItem> navigationItems = FlattenNavigationItems(root, true);

            for (int i = 0; i < navigationItems.Count; i++)
            {
                newJoins[i] = joins[i];
                if (navigationItems[i].SelectItems.Count > 0)
                {
                    var properties = new Expression[navigationItems[i].SelectItems.Count];
                    for (int j = 0; j < navigationItems[i].SelectItems.Count; j++)
                    {
                        if (navigationItems[i].SelectItems[j].EdmProperty is ComputeProperty computeProperty)
                        {
                            properties[j] = new ReplaceParameterVisitor(joins[i]).Visit(computeProperty.Expression);
                        }
                        else
                        {
                            PropertyInfo property = OeEdmClrHelper.GetPropertyIgnoreCase(joins[i].Type, navigationItems[i].SelectItems[j].EdmProperty);
                            properties[j] = Expression.Property(joins[i], property);
                        }
                    }
                    Expression newTupleExpression = OeExpressionHelper.CreateTupleExpression(properties);

                    if (i > 0 && navigationItems[i].EdmProperty.Type.IsNullable)
                    {
                        UnaryExpression nullConstant = Expression.Convert(OeConstantToVariableVisitor.NullConstantExpression, newTupleExpression.Type);
                        newTupleExpression = Expression.Condition(Expression.Equal(joins[i], OeConstantToVariableVisitor.NullConstantExpression), nullConstant, newTupleExpression);
                    }
                    newJoins[i] = newTupleExpression;
                }
            }

            NewExpression    newSelectorBody  = OeExpressionHelper.CreateTupleExpression(newJoins);
            MethodInfo       selectMethodInfo = OeMethodInfoHelper.GetSelectMethodInfo(parameter.Type, newSelectorBody.Type);
            LambdaExpression newSelector      = Expression.Lambda(newSelectorBody, parameter);

            //Quirk EF Core 2.1.1 bug Take/Skip must be last in expression tree
            var skipTakeExpressions = new List <MethodCallExpression>();

            while (source is MethodCallExpression callExpression && (callExpression.Method.Name == nameof(Enumerable.Skip) || callExpression.Method.Name == nameof(Enumerable.Take)))
            {
                skipTakeExpressions.Add(callExpression);
                source = callExpression.Arguments[0];
            }

            source = Expression.Call(selectMethodInfo, source, newSelector);

            for (int i = skipTakeExpressions.Count - 1; i >= 0; i--)
            {
                MethodInfo skipTakeMethodInfo = skipTakeExpressions[i].Method.GetGenericMethodDefinition().MakeGenericMethod(newSelector.ReturnType);
                source = Expression.Call(skipTakeMethodInfo, source, skipTakeExpressions[i].Arguments[1]);
            }

            return(source);
        }
예제 #14
0
        private static Expression BuildSkipTakeSource(Expression source, OeQueryContext queryContext, OeSelectItem navigationItem)
        {
            bool hasSelectItems = HasSelectItems(queryContext.ODataUri.SelectAndExpand);

            source = BuildOrderBySkipToken(navigationItem, queryContext.ODataUri.OrderBy, source, queryContext.JoinBuilder, hasSelectItems);
            queryContext.JoinBuilder.Visitor.ChangeParameterType(source);

            var expressionBuilder = new OeExpressionBuilder(queryContext.JoinBuilder);

            source = expressionBuilder.ApplySkipToken(source, queryContext.SkipTokenNameValues, queryContext.ODataUri.OrderBy, queryContext.IsDatabaseNullHighestValue);
            source = expressionBuilder.ApplyOrderBy(source, queryContext.ODataUri.OrderBy);
            source = expressionBuilder.ApplySkip(source, queryContext.ODataUri.Skip, queryContext.ODataUri.Path);
            return(expressionBuilder.ApplyTake(source, queryContext.ODataUri.Top, queryContext.ODataUri.Path));
        }