/// <summary> /// Binds a service operation segment. /// </summary> /// <param name="segmentToken">The segment which represents a service operation.</param> /// <param name="serviceOperation">The service operation to bind.</param> /// <returns>The bound node.</returns> private QueryNode BindServiceOperation(SegmentQueryToken segmentToken, IEdmFunctionImport serviceOperation) { Debug.Assert(segmentToken != null, "segmentToken != null"); Debug.Assert(serviceOperation != null, "serviceOperation != null"); Debug.Assert(segmentToken.Name == serviceOperation.Name, "The segment represents a different service operation."); //// This is a metadata copy of the RequestUriProcessor.CreateSegmentForServiceOperation //// The WCF DS checks the verb in this place, we can't do that here // All service operations other than those returning IQueryable MUST NOT have () appended to the URI // V1/V2 behavior: if it's IEnumerable<T>, we do not allow () either, because it's not further composable. ODataServiceOperationResultKind? resultKind = serviceOperation.GetServiceOperationResultKind(this.model); if (resultKind != ODataServiceOperationResultKind.QueryWithMultipleResults && segmentToken.NamedValues != null) { throw new ODataException(Strings.MetadataBinder_NonQueryableServiceOperationWithKeyLookup(segmentToken.Name)); } if (!resultKind.HasValue) { throw new ODataException(Strings.MetadataBinder_ServiceOperationWithoutResultKind(serviceOperation.Name)); } IEnumerable<QueryNode> serviceOperationParameters = this.BindServiceOperationParameters(serviceOperation); switch (resultKind.Value) { case ODataServiceOperationResultKind.QueryWithMultipleResults: if (serviceOperation.ReturnType.TypeKind() != EdmTypeKind.Entity) { throw new ODataException(Strings.MetadataBinder_QueryServiceOperationOfNonEntityType(serviceOperation.Name, resultKind.Value.ToString(), serviceOperation.ReturnType.ODataFullName())); } CollectionServiceOperationQueryNode collectionServiceOperationQueryNode = new CollectionServiceOperationQueryNode() { ServiceOperation = serviceOperation, Parameters = serviceOperationParameters }; if (segmentToken.NamedValues != null) { return this.BindKeyValues(collectionServiceOperationQueryNode, segmentToken.NamedValues); } else { return collectionServiceOperationQueryNode; } case ODataServiceOperationResultKind.QueryWithSingleResult: if (!serviceOperation.ReturnType.IsODataEntityTypeKind()) { throw new ODataException(Strings.MetadataBinder_QueryServiceOperationOfNonEntityType(serviceOperation.Name, resultKind.Value.ToString(), serviceOperation.ReturnType.ODataFullName())); } return new SingleValueServiceOperationQueryNode() { ServiceOperation = serviceOperation, Parameters = serviceOperationParameters }; case ODataServiceOperationResultKind.DirectValue: if (serviceOperation.ReturnType.IsODataPrimitiveTypeKind()) { // Direct primitive values are composable, $value is allowed on them. return new SingleValueServiceOperationQueryNode() { ServiceOperation = serviceOperation, Parameters = serviceOperationParameters }; } else { // Direct non-primitive values are not composable at all return new UncomposableServiceOperationQueryNode() { ServiceOperation = serviceOperation, Parameters = serviceOperationParameters }; } case ODataServiceOperationResultKind.Enumeration: case ODataServiceOperationResultKind.Void: // Enumeration and void service operations are not composable return new UncomposableServiceOperationQueryNode() { ServiceOperation = serviceOperation, Parameters = serviceOperationParameters }; default: throw new ODataException(Strings.General_InternalError(InternalErrorCodes.MetadataBinder_BindServiceOperation)); } }
/// <summary> /// Translates a service operation node which returns a collection of entities. /// </summary> /// <param name="serviceOperationNode">The collection service operation node to translate.</param> /// <returns>Expression which evaluates to IQueryable<T> where T is the InstanceType of the ResultType of the service operation.</returns> protected abstract Expression TranslateCollectionServiceOperation(CollectionServiceOperationQueryNode serviceOperationNode);