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); }
/// <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); }
private IncludeExpression CreateIncludeCall(Expression caller, NavigationTreeNode node, ParameterExpression rootParameter, SourceMapping sourceMapping) => node.Navigation.IsCollection() ? CreateIncludeCollectionCall(caller, node, rootParameter, sourceMapping) : CreateIncludeReferenceCall(caller, node, rootParameter, sourceMapping);
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)); }
private void Remove(NavigationTreeNode childNode) { childNodes.Remove(childNode); childNode.Parent = null; }
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); }