private void TestCast <TParam, TReturn>(EntityCollectionNode source, IEdmEntityType cast, Expression <Func <TParam, TReturn> > expectedExpression) { var node = new EntityCollectionCastNode(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)); }
/// <summary> /// Tries to bind key values to a key lookup on a collection. /// </summary> /// <param name="collectionNode">Already bound collection node.</param> /// <param name="namedValues">The named value tokens to bind.</param> /// <param name="model">The model to be used.</param> /// <param name="collectionItemEntityType">The type of a single item in a collection to apply the key value to.</param> /// <param name="keyLookupNode">The bound key lookup.</param> /// <returns>Returns true if binding succeeded.</returns> private bool TryBindToDeclaredKey(EntityCollectionNode collectionNode, IEnumerable <NamedValue> namedValues, IEdmModel model, IEdmEntityType collectionItemEntityType, out QueryNode keyLookupNode) { Dictionary <string, IEdmProperty> keys = new Dictionary <string, IEdmProperty>(StringComparer.Ordinal); foreach (IEdmStructuralProperty property in collectionItemEntityType.Key()) { keys[property.Name] = property; } return(TryBindToKeys(collectionNode, namedValues, model, collectionItemEntityType, keys, out keyLookupNode)); }
public void TranslatorShouldConvertWeaklyBackedEntityCollectionCast() { EntityCollectionNode source = this.CollectionNavigationFromParameter("c"); QueryNode node = new EntityCollectionCastNode(source, this.weaklyBackedCustomerEdmType); var result = this.testSubject.TranslateNode(node); var parameterExpression = Expression.Parameter(typeof(Customer), "c"); var propertyExpression = Expression.Property(parameterExpression, "OtherFriends"); var expected = Expression.Call(typeof(DataServiceProviderMethods), "OfType", new[] { typeof(Customer), typeof(object) }, propertyExpression, Expression.Constant(this.weaklyBackedDerivedType)); expected = Expression.Call(typeof(Enumerable), "Cast", new[] { typeof(object) }, expected); CompareExpressions(expected, result); }
/// <summary> /// Checks whether a query node is a collection query node representing a collection of entities. /// </summary> /// <param name="query">The <see cref="QueryNode"/> to check.</param> /// <returns>The converted <see cref="CollectionNode"/> or null if <paramref name="query"/> is not an entity collection node.</returns> internal static EntityCollectionNode AsEntityCollectionNode(this QueryNode query) { Debug.Assert(query != null, "query != null"); EntityCollectionNode collectionNode = query as EntityCollectionNode; if (collectionNode != null && collectionNode.ItemType != null && collectionNode.ItemType.IsODataEntityTypeKind()) { return(collectionNode); } return(null); }
/// <summary> /// Tries to bind key values to a key lookup on a collection. /// </summary> /// <param name="collectionNode">Already bound collection node.</param> /// <param name="namedValues">The named value tokens to bind.</param> /// <param name="model">The model to be used.</param> /// <param name="collectionItemEntityType">The type of a single item in a collection to apply the key value to.</param> /// <param name="keyLookupNode">The bound key lookup.</param> /// <returns>Returns true if binding succeeded.</returns> private bool TryBindToDeclaredAlternateKey(EntityCollectionNode collectionNode, IEnumerable <NamedValue> namedValues, IEdmModel model, IEdmEntityType collectionItemEntityType, out QueryNode keyLookupNode) { IEnumerable <IDictionary <string, IEdmProperty> > alternateKeys = model.GetAlternateKeysAnnotation(collectionItemEntityType); foreach (IDictionary <string, IEdmProperty> keys in alternateKeys) { if (TryBindToKeys(collectionNode, namedValues, model, collectionItemEntityType, keys, out keyLookupNode)) { return(true); } } keyLookupNode = null; return(false); }
/// <summary> /// Binds key values to a key lookup on a collection. /// </summary> /// <param name="collectionNode">Already bound collection node.</param> /// <param name="namedValues">The named value tokens to bind.</param> /// <param name="model">The model to be used.</param> /// <param name="collectionItemEntityType">The type of a single item in a collection to apply the key value to.</param> /// <param name="keys">Dictionary of aliases to structural property names for the key.</param> /// <param name="keyLookupNode">The bound key lookup.</param> /// <returns>Returns true if binding succeeded.</returns> private bool TryBindToKeys(EntityCollectionNode collectionNode, IEnumerable <NamedValue> namedValues, IEdmModel model, IEdmEntityType collectionItemEntityType, IDictionary <string, IEdmProperty> keys, out QueryNode keyLookupNode) { List <KeyPropertyValue> keyPropertyValues = new List <KeyPropertyValue>(); HashSet <string> keyPropertyNames = new HashSet <string>(StringComparer.Ordinal); foreach (NamedValue namedValue in namedValues) { KeyPropertyValue keyPropertyValue; if (!this.TryBindKeyPropertyValue(namedValue, collectionItemEntityType, keys, out keyPropertyValue)) { keyLookupNode = null; return(false); } Debug.Assert(keyPropertyValue != null, "keyPropertyValue != null"); Debug.Assert(keyPropertyValue.KeyProperty != null, "keyPropertyValue.KeyProperty != null"); if (!keyPropertyNames.Add(keyPropertyValue.KeyProperty.Name)) { throw new ODataException(ODataErrorStrings.MetadataBinder_DuplicitKeyPropertyInKeyValues(keyPropertyValue.KeyProperty.Name)); } keyPropertyValues.Add(keyPropertyValue); } if (keyPropertyValues.Count == 0) { // No key values specified, for example '/Customers()', do not include the key lookup at all keyLookupNode = collectionNode; return(true); } else if (keyPropertyValues.Count != collectionItemEntityType.Key().Count()) { keyLookupNode = null; return(false); } else { keyLookupNode = new KeyLookupNode(collectionNode, new ReadOnlyCollection <KeyPropertyValue>(keyPropertyValues)); return(true); } }
/// <summary> /// Binds key values to a key lookup on a collection. /// </summary> /// <param name="collectionNode">Already bound collection node.</param> /// <param name="namedValues">The named value tokens to bind.</param> /// <returns>The bound key lookup.</returns> internal QueryNode BindKeyValues(EntityCollectionNode collectionNode, IEnumerable <NamedValue> namedValues) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(namedValues != null, "namedValues != null"); Debug.Assert(collectionNode != null, "CollectionNode != null"); IEdmEntityTypeReference collectionItemType = collectionNode.EntityItemType; List <KeyPropertyValue> keyPropertyValues = new List <KeyPropertyValue>(); IEdmEntityType collectionItemEntityType = collectionItemType.EntityDefinition(); HashSet <string> keyPropertyNames = new HashSet <string>(StringComparer.Ordinal); foreach (NamedValue namedValue in namedValues) { KeyPropertyValue keyPropertyValue = this.BindKeyPropertyValue(namedValue, collectionItemEntityType); Debug.Assert(keyPropertyValue != null, "keyPropertyValue != null"); Debug.Assert(keyPropertyValue.KeyProperty != null, "keyPropertyValue.KeyProperty != null"); if (!keyPropertyNames.Add(keyPropertyValue.KeyProperty.Name)) { throw new ODataException(ODataErrorStrings.MetadataBinder_DuplicitKeyPropertyInKeyValues(keyPropertyValue.KeyProperty.Name)); } keyPropertyValues.Add(keyPropertyValue); } if (keyPropertyValues.Count == 0) { // No key values specified, for example '/Customers()', do not include the key lookup at all return(collectionNode); } else if (keyPropertyValues.Count != collectionItemEntityType.Key().Count()) { throw new ODataException(ODataErrorStrings.MetadataBinder_NotAllKeyPropertiesSpecifiedInKeyValues(collectionNode.ItemType.ODataFullName())); } else { return(new KeyLookupNode(collectionNode, new ReadOnlyCollection <KeyPropertyValue>(keyPropertyValues))); } }
/// <summary> /// Binds key values to a key lookup on a collection. /// </summary> /// <param name="collectionNode">Already bound collection node.</param> /// <param name="namedValues">The named value tokens to bind.</param> /// <param name="model">The model to be used.</param> /// <returns>The bound key lookup.</returns> internal QueryNode BindKeyValues(EntityCollectionNode collectionNode, IEnumerable <NamedValue> namedValues, IEdmModel model) { Debug.Assert(namedValues != null, "namedValues != null"); Debug.Assert(collectionNode != null, "CollectionNode != null"); Debug.Assert(model != null, "model != null"); IEdmEntityTypeReference collectionItemType = collectionNode.EntityItemType; IEdmEntityType collectionItemEntityType = collectionItemType.EntityDefinition(); QueryNode keyLookupNode; if (TryBindToDeclaredKey(collectionNode, namedValues, model, collectionItemEntityType, out keyLookupNode)) { return(keyLookupNode); } else if (TryBindToDeclaredAlternateKey(collectionNode, namedValues, model, collectionItemEntityType, out keyLookupNode)) { return(keyLookupNode); } else { throw new ODataException(ODataErrorStrings.MetadataBinder_NotAllKeyPropertiesSpecifiedInKeyValues(collectionNode.ItemType.FullName())); } }
/// <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)); } }