/// <summary> /// Builds an appropriate navigation query node (collection or single) for the given property and parent node. /// </summary> /// <param name="property">Navigation property.</param> /// <param name="parent">Parent Node.</param> /// <param name="namedValues">Named values (key values) that were included in the node we are binding, if any.</param> /// <param name="state">State of binding.</param> /// <param name="keyBinder">Object to perform binding on any key values that are present.</param> /// <returns>A new CollectionNavigationNode or SingleNavigationNode to capture the navigation propety access.</returns> internal static QueryNode GetNavigationNode(IEdmNavigationProperty property, SingleEntityNode parent, IEnumerable <NamedValue> namedValues, BindingState state, KeyBinder keyBinder) { ExceptionUtils.CheckArgumentNotNull(property, "property"); ExceptionUtils.CheckArgumentNotNull(parent, "parent"); ExceptionUtils.CheckArgumentNotNull(state, "state"); ExceptionUtils.CheckArgumentNotNull(keyBinder, "keyBinder"); // Handle collection navigation property if (property.TargetMultiplicity() == EdmMultiplicity.Many) { CollectionNavigationNode collectionNavigationNode = new CollectionNavigationNode(property, parent); // Doing key lookup on the collection navigation property if (namedValues != null) { return(keyBinder.BindKeyValues(collectionNavigationNode, namedValues, state.Model)); } // Otherwise it's just a normal collection of entities return(collectionNavigationNode); } Debug.Assert(namedValues == null || !namedValues.Any(), "namedValues should not exist if it isn't a colleciton"); // Otherwise it's a single navigation property return(new SingleNavigationNode(property, parent)); }
private void TestCast <TParam, TReturn>(SingleEntityNode source, IEdmEntityType cast, Expression <Func <TParam, TReturn> > expectedExpression) { var node = new SingleEntityCastNode(source, cast); var result = this.testSubject.TranslateNode(node); CompareExpressions(expectedExpression.Body, result); }
/// <summary> /// Binds a DottedIdentifierToken and it's parent node (if needed). /// </summary> /// <param name="dottedIdentifierToken">Token to bind to metadata.</param> /// <param name="state">State of the Binding.</param> /// <returns>A bound node representing the cast.</returns> internal QueryNode BindDottedIdentifier(DottedIdentifierToken dottedIdentifierToken, BindingState state) { DebugUtils.CheckNoExternalCallers(); ExceptionUtils.CheckArgumentNotNull(dottedIdentifierToken, "castToken"); ExceptionUtils.CheckArgumentNotNull(state, "state"); QueryNode parent; IEdmType parentType; if (dottedIdentifierToken.NextToken == null) { parent = NodeFactory.CreateRangeVariableReferenceNode(state.ImplicitRangeVariable); parentType = state.ImplicitRangeVariable.TypeReference.Definition; } else { parent = this.bindMethod(dottedIdentifierToken.NextToken); parentType = parent.GetEdmType(); } SingleEntityNode parentAsSingleValue = parent as SingleEntityNode; IEdmSchemaType childType = UriEdmHelpers.FindTypeFromModel(state.Model, dottedIdentifierToken.Identifier); IEdmEntityType childEntityType = childType as IEdmEntityType; if (childEntityType == null) { FunctionCallBinder functionCallBinder = new FunctionCallBinder(bindMethod); QueryNode functionCallNode; if (functionCallBinder.TryBindDottedIdentifierAsFunctionCall(dottedIdentifierToken, parentAsSingleValue, state, out functionCallNode)) { return(functionCallNode); } else { throw new ODataException(ODataErrorStrings.CastBinder_ChildTypeIsNotEntity(dottedIdentifierToken.Identifier)); } } // Check whether childType is a derived type of the type of its parent node UriEdmHelpers.CheckRelatedTo(parentType, childType); EntityCollectionNode parentAsCollection = parent as EntityCollectionNode; if (parentAsCollection != null) { return(new EntityCollectionCastNode(parentAsCollection, childEntityType)); } // parent can be null for casts on the implicit parameter; this is OK if (parent == null) { return(new SingleEntityCastNode(null, childEntityType)); } Debug.Assert(parentAsSingleValue != null, "If parent of the cast node was not collection, it should be a single value."); return(new SingleEntityCastNode(parentAsSingleValue, childEntityType)); }
public void TranslatorShouldConvertWeaklyBackedSingleEntityCast() { SingleEntityNode source = EntityParameter <Customer>("c"); QueryNode node = new SingleEntityCastNode(source, this.weaklyBackedCustomerEdmType); var result = this.testSubject.TranslateNode(node); var parameterExpression = Expression.Parameter(typeof(Customer), "c"); var expected = Expression.Call(typeof(DataServiceProviderMethods), "TypeAs", new[] { typeof(object) }, parameterExpression, Expression.Constant(this.weaklyBackedDerivedType)); CompareExpressions(expected, result); }
/// <summary> /// Ensures that the parent node is of entity type, throwing if it is not. /// </summary> /// <param name="parent">Parent node to a navigation property.</param> /// <returns>The given parent node as a SingleEntityNode.</returns> internal static SingleEntityNode EnsureParentIsEntityForNavProp(SingleValueNode parent) { ExceptionUtils.CheckArgumentNotNull(parent, "parent"); SingleEntityNode parentEntity = parent as SingleEntityNode; if (parentEntity == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_NavigationPropertyNotFollowingSingleEntityType); } return(parentEntity); }
private void TestNavigation <TParam, TReturn>(SingleEntityNode source, IEdmNavigationProperty navigation, Expression <Func <TParam, TReturn> > expectedExpression) { QueryNode node; if (navigation.Type.IsCollection()) { node = new CollectionNavigationNode(navigation, source); } else { node = new SingleNavigationNode(navigation, source); } var result = this.testSubject.TranslateNode(node); CompareExpressions(expectedExpression.Body, result); }
/// <summary> /// Build a SingleValueFunctionCallNode for a function that isn't bound to a BuiltInFunction /// </summary> /// <param name="functionCallTokenName">Name for the function</param> /// <param name="args">list of already bound query nodes for this function</param> /// <returns>A single value function call node bound to this function.</returns> private SingleValueNode CreateUnboundFunctionNode(string functionCallTokenName, List <QueryNode> args) { // need to figure out the return type and check the correct number of arguments based on the function name IEdmTypeReference returnType = null; switch (functionCallTokenName) { case ExpressionConstants.UnboundFunctionIsOf: { returnType = ValidateAndBuildIsOfArgs(state, ref args); break; } case ExpressionConstants.UnboundFunctionCast: { returnType = ValidateAndBuildCastArgs(state, ref args); if (returnType.IsEntity()) { IEdmEntityTypeReference returnEntityType = returnType.AsEntity(); SingleEntityNode entityNode = args.ElementAt(0) as SingleEntityNode; if (entityNode != null) { return(new SingleEntityFunctionCallNode(functionCallTokenName, args, returnEntityType, entityNode.NavigationSource)); } } break; } default: { break; } } // we have everything else we need, so return the new SingleValueFunctionCallNode. return(new SingleValueFunctionCallNode(functionCallTokenName, args, returnType)); }
/// <summary> /// Binds a <see cref="InnerPathToken"/>. /// This includes more than just navigations - it includes complex property access and primitive collections. /// </summary> /// <param name="segmentToken">The segment token to bind.</param> /// <returns>The bound node.</returns> internal QueryNode BindInnerPathSegment(InnerPathToken segmentToken) { FunctionCallBinder functionCallBinder = new FunctionCallBinder(this.bindMethod, state); // First we get the parent node QueryNode parent = this.DetermineParentNode(segmentToken, state); Debug.Assert(parent != null, "parent should never be null"); SingleValueNode singleValueParent = parent as SingleValueNode; if (singleValueParent == null) { QueryNode boundFunction; if (functionCallBinder.TryBindInnerPathAsFunctionCall(segmentToken, parent, out boundFunction)) { return(boundFunction); } throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyAccessSourceNotSingleValue(segmentToken.Identifier)); } // Using the parent and name of this token, we try to get the IEdmProperty it represents IEdmProperty property = BindProperty(singleValueParent.TypeReference, segmentToken.Identifier, this.Resolver); if (property == null) { QueryNode boundFunction; if (functionCallBinder.TryBindInnerPathAsFunctionCall(segmentToken, parent, out boundFunction)) { return(boundFunction); } if (singleValueParent.TypeReference != null && !singleValueParent.TypeReference.Definition.IsOpenType()) { throw new ODataException( ODataErrorStrings.MetadataBinder_PropertyNotDeclared( parent.GetEdmTypeReference().FullName(), segmentToken.Identifier)); } return(new SingleValueOpenPropertyAccessNode(singleValueParent, segmentToken.Identifier)); } if (property.Type.IsODataComplexTypeKind()) { return(new SingleValuePropertyAccessNode(singleValueParent, property)); } // Note - this means nonentity collection (primitive or complex) if (property.Type.IsNonEntityCollectionType()) { return(new CollectionPropertyAccessNode(singleValueParent, property)); } IEdmNavigationProperty navigationProperty = property as IEdmNavigationProperty; if (navigationProperty == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_IllegalSegmentType(property.Name)); } SingleEntityNode parentEntity = EnsureParentIsEntityForNavProp(singleValueParent); return(GetNavigationNode(navigationProperty, parentEntity, segmentToken.NamedValues, state, new KeyBinder(this.bindMethod))); }
private string BindNavigationPropertyNode(SingleEntityNode singleEntityNode, IEdmNavigationProperty edmNavigationProperty) { return(Bind(singleEntityNode) + "." + edmNavigationProperty.Name); }
/// <summary> /// Binds a DottedIdentifierToken and it's parent node (if needed). /// </summary> /// <param name="dottedIdentifierToken">Token to bind to metadata.</param> /// <param name="state">State of the Binding.</param> /// <returns>A bound node representing the cast.</returns> internal QueryNode BindDottedIdentifier(DottedIdentifierToken dottedIdentifierToken, BindingState state) { ExceptionUtils.CheckArgumentNotNull(dottedIdentifierToken, "castToken"); ExceptionUtils.CheckArgumentNotNull(state, "state"); QueryNode parent = null; IEdmType parentType = null; if (state.ImplicitRangeVariable != null) { if (dottedIdentifierToken.NextToken == null) { parent = NodeFactory.CreateRangeVariableReferenceNode(state.ImplicitRangeVariable); parentType = state.ImplicitRangeVariable.TypeReference.Definition; } else { parent = this.bindMethod(dottedIdentifierToken.NextToken); parentType = parent.GetEdmType(); } } SingleEntityNode parentAsSingleValue = parent as SingleEntityNode; IEdmSchemaType childType = UriEdmHelpers.FindTypeFromModel(state.Model, dottedIdentifierToken.Identifier); IEdmStructuredType childStructuredType = childType as IEdmStructuredType; if (childStructuredType == null) { FunctionCallBinder functionCallBinder = new FunctionCallBinder(bindMethod); QueryNode functionCallNode; if (functionCallBinder.TryBindDottedIdentifierAsFunctionCall(dottedIdentifierToken, parentAsSingleValue, state, out functionCallNode)) { return(functionCallNode); } else if ((!string.IsNullOrEmpty(dottedIdentifierToken.Identifier)) && (dottedIdentifierToken.Identifier[dottedIdentifierToken.Identifier.Length - 1] == '\'')) { // check if it is enum or not EnumBinder enumBinder = new EnumBinder(this.bindMethod); QueryNode enumNode; if (enumBinder.TryBindDottedIdentifierAsEnum(dottedIdentifierToken, parentAsSingleValue, state, out enumNode)) { return(enumNode); } else { throw new ODataException(ODataErrorStrings.Binder_IsNotValidEnumConstant(dottedIdentifierToken.Identifier)); } } else { IEdmTypeReference edmTypeReference = UriEdmHelpers.FindTypeFromModel(state.Model, dottedIdentifierToken.Identifier).ToTypeReference(); if (edmTypeReference is IEdmPrimitiveTypeReference || edmTypeReference is IEdmEnumTypeReference) { return(new ConstantNode(dottedIdentifierToken.Identifier, dottedIdentifierToken.Identifier)); } else { throw new ODataException(ODataErrorStrings.CastBinder_ChildTypeIsNotEntity(dottedIdentifierToken.Identifier)); } } } // Check whether childType is a derived type of the type of its parent node UriEdmHelpers.CheckRelatedTo(parentType, childType); IEdmEntityType childEntityType = childStructuredType as IEdmEntityType; if (childEntityType != null) { EntityCollectionNode parentAsCollection = parent as EntityCollectionNode; if (parentAsCollection != null) { return(new EntityCollectionCastNode(parentAsCollection, childEntityType)); } // parent can be null for casts on the implicit parameter; this is OK if (parent == null) { return(new SingleEntityCastNode(null, childEntityType)); } Debug.Assert(parentAsSingleValue != null, "If parent of the cast node was not collection, it should be a single value."); return(new SingleEntityCastNode(parentAsSingleValue, childEntityType)); } else { IEdmComplexType childComplexType = childStructuredType as IEdmComplexType; Debug.Assert(childComplexType != null, "If it is not entity type, it should be complex type"); CollectionPropertyAccessNode parentAsCollectionProperty = parent as CollectionPropertyAccessNode; if (parentAsCollectionProperty != null) { return(new CollectionPropertyCastNode(parentAsCollectionProperty, childComplexType)); } // parent can be null for casts on the implicit parameter; this is OK if (parent == null) { return(new SingleValueCastNode(null, childComplexType)); } SingleValueNode parentAsSingleValueNode = parent as SingleValueNode; Debug.Assert(parentAsSingleValueNode != null, "If parent of the cast node was not collection, it should be a single value."); return(new SingleValueCastNode(parentAsSingleValueNode, childComplexType)); } }
private string BindNavigationPropertyNode(SingleEntityNode singleEntityNode, IEdmNavigationProperty edmNavigationProperty) { return Bind(singleEntityNode) + "." + edmNavigationProperty.Name; }
static string BindNavigationPropertyNode(SingleEntityNode singleEntityNode, IEdmNavigationProperty edmNavigationProperty, List <DbParameter> pars, DbUtility dbUtility) { return(Bind(singleEntityNode, pars, dbUtility) + "." + edmNavigationProperty.Name); }