private static IList<EntitySet> GetModelEntitySets(this DbModel model, MethodInfo methodInfo, FunctionAttribute functionAttribute) { ParameterInfo returnParameterInfo = methodInfo.ReturnParameter; if (returnParameterInfo == null || returnParameterInfo.ParameterType == typeof(void)) { throw new NotSupportedException($"The return parameter type of {methodInfo.Name} is not supported."); } if (functionAttribute.Type == FunctionType.StoredProcedure && returnParameterInfo.ParameterType != typeof(int)) { // returnParameterInfo.ParameterType is ObjectResult<T>. Type[] returnParameterClrTypes = methodInfo.GetStoredProcedureReturnTypes().ToArray(); if (returnParameterClrTypes.Length > 1) { // Stored procedure has more than one result. // EdmFunctionPayload.EntitySets must be provided. Otherwise, an ArgumentException will be thrown: // The EntitySets parameter must not be null for functions that return multiple result sets. return returnParameterClrTypes.Select(clrType => { EntitySet modelEntitySet = model .ConceptualModel .Container .EntitySets .FirstOrDefault(entitySet => entitySet.ElementType.FullName.EqualsOrdinal(clrType.FullName)); if (modelEntitySet == null) { throw new NotSupportedException( $"{clrType.FullName} for method {methodInfo.Name} is not supported in conceptual model as entity set."); } return modelEntitySet; }).ToArray(); } } // Do not return new EntitySet[0], which causes a ArgumentException: // The number of entity sets should match the number of return parameters. return null; }
private static IList<FunctionParameter> GetModelReturnParameters( this DbModel model, MethodInfo methodInfo, FunctionAttribute functionAttribute) { ParameterInfo returnParameterInfo = methodInfo.ReturnParameter; if (returnParameterInfo == null || returnParameterInfo.ParameterType == typeof(void)) { throw new NotSupportedException($"The return parameter type of {methodInfo.Name} is not supported."); } ParameterAttribute returnParameterAttribute = returnParameterInfo.GetCustomAttribute<ParameterAttribute>(); ResultTypeAttribute[] returnTypeAttributes = methodInfo.GetCustomAttributes<ResultTypeAttribute>().ToArray(); IEnumerable<EdmType> modelReturnParameterEdmTypes; if (functionAttribute.Type == FunctionType.StoredProcedure) { if (returnParameterAttribute != null) { throw new NotSupportedException( $"{nameof(ParameterAttribute)} for method {methodInfo.Name} is not supported."); } modelReturnParameterEdmTypes = methodInfo .GetStoredProcedureReturnTypes() .Select(clrType => model.GetModelStructualType(clrType, methodInfo)); } else { if (returnTypeAttributes.Any()) { throw new NotSupportedException( $"{nameof(ResultTypeAttribute)} for method {methodInfo.Name} is not supported."); } if (functionAttribute.Type == FunctionType.TableValuedFunction) { // returnParameterInfo.ParameterType is IQueryable<T>. Type returnParameterClrType = returnParameterInfo.ParameterType.GetGenericArguments().Single(); StructuralType modelReturnParameterStructuralType = model.GetModelStructualType( returnParameterClrType, methodInfo); modelReturnParameterEdmTypes = Enumerable.Repeat(modelReturnParameterStructuralType, 1); } else { Type returnParameterClrType = returnParameterInfo.ParameterType; Type returnParameterAttributeClrType = returnParameterAttribute?.ClrType; if (returnParameterAttributeClrType != null && returnParameterAttributeClrType != returnParameterClrType) { throw new NotSupportedException( $"Return parameter of method {methodInfo.Name} is of {returnParameterClrType.FullName}, but its {nameof(ParameterAttribute)}.{nameof(ParameterAttribute.ClrType)} has a fifferent type {returnParameterAttributeClrType.FullName}"); } PrimitiveType returnParameterPrimitiveType = model.GetModelPrimitiveType( returnParameterClrType, methodInfo); modelReturnParameterEdmTypes = Enumerable.Repeat(returnParameterPrimitiveType, 1); } } return modelReturnParameterEdmTypes .Select((edmType, index) => FunctionParameter.Create( $"ReturnType{index}", edmType.GetCollectionType(), ParameterMode.ReturnValue)) .ToArray(); }