Example #1
0
        private Expression TryBindProperty(Expression originalExpression, Expression newExpression, string navigationMemberName)
        {
            if (newExpression is NavigationBindingExpression navigationBindingExpression)
            {
                if (navigationBindingExpression.RootParameter == _rootParameter)
                {
                    var navigation = navigationBindingExpression.EntityType.FindNavigation(navigationMemberName);
                    if (navigation != null)
                    {
                        var navigationTreeNode = NavigationTreeNode.Create(
                            navigationBindingExpression.SourceMapping, navigation, navigationBindingExpression.NavigationTreeNode, _bindInclude);

                        return(new NavigationBindingExpression(
                                   navigationBindingExpression.RootParameter,
                                   navigationTreeNode,
                                   navigation.GetTargetType(),
                                   navigationBindingExpression.SourceMapping,
                                   originalExpression.Type));
                    }
                }
            }
            else
            {
                foreach (var sourceMapping in _sourceMappings)
                {
                    var candidates = sourceMapping.NavigationTree.Flatten()
                                     .SelectMany(n => n.FromMappings, (n, m) => (navigationTreeNode: n, path: m)).ToList();
                    var match = TryFindMatchingNavigationTreeNode(originalExpression, candidates);
                    if (match.navigationTreeNode != null)
                    {
                        return(new NavigationBindingExpression(
                                   match.rootParameter,
                                   match.navigationTreeNode,
                                   match.navigationTreeNode.Navigation?.GetTargetType() ?? sourceMapping.RootEntityType,
                                   sourceMapping,
                                   originalExpression.Type));
                    }
                }
            }

            return(null);
        }
Example #2
0
        /// <summary>
        /// Creates a navigation node from the given <paramref name="element"/>.
        /// </summary>
        /// <param name="element">The current XML element.</param>
        /// <param name="canHaveChildren">Whether the element can have children.</param>
        /// <returns>
        /// The new <see cref="NavigationTreeNode"/>.
        /// </returns>
        /// <exception cref="XmlNavigationException">When the node is invalid.</exception>
        protected virtual NavigationTreeNode CreateNode(XElement element, bool canHaveChildren)
        {
            var node = CreateNodeFromXml(element);

            foreach (var attr in element.Attributes())
            {
                var attrName = attr.Name.LocalName ?? string.Empty;
                if (attrName.Length <= RouteParamAttributePrefix.Length ||
                    !attrName.StartsWith(RouteParamAttributePrefix) ||
                    string.Equals(RouteNameAttributeName, attrName, StringComparison.OrdinalIgnoreCase) ||
                    string.Equals(RouteNameAttributeAltName, attrName, StringComparison.OrdinalIgnoreCase))
                {
                    // We are going to ignore the "route-name" attribute
                    continue;
                }

                var name = attrName.Substring(RouteParamAttributePrefix.Length);
                if (!string.IsNullOrEmpty(name))
                {
                    // We got a valid parameter name, we can continue
                    node.RouteParameters.TryAdd(name, attr.Value);
                }
            }

            // Retrieves a value indicating which kind of user the node should be hidden from
            var hideFrom = GetAttributeValue(element, HideFromAttributeName) ??
                           GetAttributeValue(element, HideFromAttributeAltName);

            if (!string.IsNullOrWhiteSpace(hideFrom))
            {
                // Determine if the hide-from value is valid
                if (!Enum.TryParse <HideNodeFrom>(hideFrom, true, out var result))
                {
                    // Unknown value
                    throw new XmlNavigationException(
                              $"The value '{hideFrom}' is not allowed for the '{HideFromAttributeName}' attribute."
                              );
                }

                node.HideNodeFrom = result;
            }

            // Determine if the node can have children
            var navigationNode = new NavigationTreeNode(node);

            if (!canHaveChildren)
            {
                // The node isn't allowed to have children, how sad
                return(navigationNode);
            }

            // Retrieve all the children for the node
            var childElements = element.Elements(NodeElementName);

            foreach (var child in childElements)
            {
                var childNode = CreateNode(child, true);
                navigationNode.AddChild(childNode);
            }

            // Done
            return(navigationNode);
        }
Example #3
0
 private IncludeExpression CreateIncludeCall(Expression caller, NavigationTreeNode node, ParameterExpression rootParameter, SourceMapping sourceMapping)
 => node.Navigation.IsCollection()
     ? CreateIncludeCollectionCall(caller, node, rootParameter, sourceMapping)
     : CreateIncludeReferenceCall(caller, node, rootParameter, sourceMapping);
Example #4
0
        private IncludeExpression CreateIncludeCollectionCall(Expression caller, NavigationTreeNode node, ParameterExpression rootParameter, SourceMapping sourceMapping)
        {
            var included = CollectionNavigationRewritingVisitor.CreateCollectionNavigationExpression(node, rootParameter, sourceMapping);

            return(new IncludeExpression(caller, included, node.Navigation));
        }
Example #5
0
 private void Remove(NavigationTreeNode childNode)
 {
     childNodes.Remove(childNode);
     childNode.Parent = null;
 }
Example #6
0
        public static Expression CreateCollectionNavigationExpression(
            NavigationTreeNode navigationTreeNode, ParameterExpression rootParameter, SourceMapping sourceMapping)
        {
            var collectionEntityType = navigationTreeNode.Navigation.ForeignKey.DeclaringEntityType;

            Expression operand;

            if (navigationTreeNode.IncludeState == NavigationState.Pending ||
                navigationTreeNode.ExpansionState == NavigationState.Pending)
            {
                var entityQueryable = (Expression)NullAsyncQueryProvider.Instance.CreateEntityQueryableExpression(collectionEntityType.ClrType);

                var outerBinding = new NavigationBindingExpression(
                    rootParameter,
                    navigationTreeNode.Parent,
                    navigationTreeNode.Navigation.DeclaringEntityType,
                    sourceMapping,
                    navigationTreeNode.Navigation.DeclaringEntityType.ClrType);

                var outerKeyAccess = NavigationExpansionHelpers.CreateKeyAccessExpression(
                    outerBinding,
                    navigationTreeNode.Navigation.ForeignKey.PrincipalKey.Properties,
                    addNullCheck: outerBinding.NavigationTreeNode.Optional);

                var collectionCurrentParameter = Expression.Parameter(
                    collectionEntityType.ClrType, collectionEntityType.ClrType.GenerateParameterName());

                var innerKeyAccess = NavigationExpansionHelpers.CreateKeyAccessExpression(
                    collectionCurrentParameter,
                    navigationTreeNode.Navigation.ForeignKey.Properties);

                var predicate = Expression.Lambda(
                    CreateKeyComparisonExpressionForCollectionNavigationSubquery(
                        outerKeyAccess,
                        innerKeyAccess,
                        outerBinding),
                    collectionCurrentParameter);

                operand = Expression.Call(
                    LinqMethodHelpers.QueryableWhereMethodInfo.MakeGenericMethod(collectionEntityType.ClrType),
                    entityQueryable,
                    predicate);
            }
            else
            {
                operand = new NavigationBindingExpression(
                    rootParameter,
                    navigationTreeNode,
                    collectionEntityType,
                    sourceMapping,
                    collectionEntityType.ClrType);
            }

            var result = NavigationExpansionHelpers.CreateNavigationExpansionRoot(
                operand, collectionEntityType, navigationTreeNode.Navigation);

            // this is needed for cases like: root.Include(r => r.Collection).ThenInclude(c => c.Reference).Select(r => r.Collection)
            // result should be elements of the collection navigation with their 'Reference' included
            var newSourceMapping = result.State.SourceMappings.Single();

            IncludeHelpers.CopyIncludeInformation(navigationTreeNode, newSourceMapping.NavigationTree, newSourceMapping);

            return(result);
        }