private static IList <FunctionParameter> GetStoreReturnParameters(DbModel model, MethodInfo methodInfo, FunctionAttribute functionAttribute)
        {
            if (methodInfo.ReturnParameter == null || (methodInfo.ReturnParameter.ParameterType == typeof(void) && functionAttribute.Type != FunctionType.StoredProcedure))
            {
                throw new NotSupportedException(string.Format("The return type of {0} is not supported.", methodInfo.Name));
            }

            var returnParameterAttribute = methodInfo.ReturnParameter.GetCustomAttribute <ParameterAttribute>();

            //var returnTypeAttributes = methodInfo.GetCustomAttributes<ResultTypeAttribute>();

            if (functionAttribute.Type == FunctionType.StoredProcedure || functionAttribute.Type == FunctionType.TableValuedFunction)
            {
                if (returnParameterAttribute != null)
                {
                    throw new NotSupportedException(string.Format("ParameterAttribute for return value of method {0} is not supported.", methodInfo.Name));
                }
            }

            if (functionAttribute.Type == FunctionType.StoredProcedure || methodInfo.ReturnType == typeof(void))
            {
                //Stored Procedure
                return(new FunctionParameter[0]);
                //return new[]
                //{
                //	FunctionParameter.Create("ReturnType", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32), ParameterMode.ReturnValue)
                //};
            }

            //if (returnTypeAttributes.Length > 0)
            //	throw new NotSupportedException(string.Format("ResultTypeAttribute for method {0} is not supported.", methodInfo.Name));

            if (functionAttribute.Type == FunctionType.TableValuedFunction)
            {
                //if (returnParameterAttribute != null)
                //	throw new NotSupportedException(string.Format("ParameterAttribute for return value of method {0} is not supported.", methodInfo.Name));

                /*
                 * <CollectionType>
                 * <RowType>
                 *      <Property Name="PersonID" Type="int" Nullable="false" />
                 *      <Property Name="FirstName" Type="nvarchar" MaxLength="50" />
                 *      <Property Name="LastName" Type="nvarchar" MaxLength="50" />
                 *      <Property Name="JobTitle" Type="nvarchar" MaxLength="50" />
                 *      <Property Name="BusinessEntityType" Type="nvarchar" MaxLength="50" />
                 * </RowType>
                 * </CollectionType>
                 */

                // returnParameterInfo.ParameterType is IQueryable<T>.
                var storeReturnParameterClrType        = methodInfo.ReturnParameter.ParameterType.GetGenericArguments().Single();
                var modelReturnParameterStructuralType = GetModelStructualType(model, storeReturnParameterClrType, methodInfo);
                var modelReturnParameterComplexType    = modelReturnParameterStructuralType as ComplexType;

                RowType storeReturnParameterRowType = null;
                if (modelReturnParameterComplexType != null)
                {
                    storeReturnParameterRowType = RowType.Create(
                        modelReturnParameterComplexType.Properties.Select(property =>
                                                                          EdmProperty.Create(property.Name, model.ProviderManifest.GetStoreType(property.TypeUsage))), null);
                }
                else
                {
                    var modelReturnParameterEntityType = modelReturnParameterStructuralType as EntityType;
                    if (modelReturnParameterEntityType != null)
                    {
                        storeReturnParameterRowType = RowType.Create(
                            modelReturnParameterEntityType.Properties.Select(property => CloneEdmProperty(property)), null);
                    }
                    else
                    {
                        throw new NotSupportedException(string.Format("Structural type {0} of method {1} cannot be converted to RowType.", modelReturnParameterStructuralType.FullName, methodInfo.Name));
                    }
                }

                return(new[]
                {
                    FunctionParameter.Create(
                        "ReturnType",
                        storeReturnParameterRowType.GetCollectionType(), // Collection of RowType.
                        ParameterMode.ReturnValue)
                });
            }

            //if (functionAttribute.Type == FunctionType.NonComposableScalarValuedFunction)
            //{
            //	// Non-composable scalar-valued function.
            //	return new FunctionParameter[0];
            //}

            // Composable scalar-valued/Aggregate/Built in/Niladic function.
            // <Function Name="ufnGetProductListPrice" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo"
            //    ReturnType ="money">
            var storeReturnParameterPrimitiveType = GetStoreParameterPrimitiveType(model, methodInfo, methodInfo.ReturnParameter, functionAttribute);

            return(new[]
            {
                FunctionParameter.Create("ReturnType", storeReturnParameterPrimitiveType, ParameterMode.ReturnValue)
            });
        }
        private static IList <FunctionParameter> GetStoreParameters(DbModel model, MethodInfo methodInfo, FunctionAttribute functionAttribute)
        {
            var parameters = GetDataParameters(methodInfo);

            if (parameters.Length > 0 && functionAttribute.Type == FunctionType.NiladicFunction)
            {
                throw new NotSupportedException(string.Format("The Niladic Function can not have parameter.", methodInfo.Name));
            }

            var result = new List <FunctionParameter>();

            for (int i = 0; i < parameters.Length; i++)
            {
                var parameterInfo   = parameters[i];
                var parameterAttrib = parameterInfo.GetCustomAttribute <ParameterAttribute>();
                var parameterName   = (parameterAttrib != null ? parameterAttrib.Name : null);
                if (string.IsNullOrWhiteSpace(parameterName))
                {
                    parameterName = parameterInfo.Name;
                }

                result.Add(
                    FunctionParameter.Create(
                        parameterName,
                        GetStoreParameterPrimitiveType(model, methodInfo, parameterInfo, functionAttribute),
                        (parameterInfo.IsOut || parameterInfo.ParameterType.IsByRef ? ParameterMode.InOut : ParameterMode.In)));
            }
            return(result.ToArray());
        }
        private static IList <FunctionParameter> GetModelReturnParameters(DbModel model, MethodInfo methodInfo, FunctionAttribute functionAttribute)
        {
            var returnParameterInfo = methodInfo.ReturnParameter;

            if (returnParameterInfo == null || (returnParameterInfo.ParameterType == typeof(void) && functionAttribute.Type != FunctionType.StoredProcedure))
            {
                throw new NotSupportedException(string.Format("The return parameter type of {0} is not supported.", methodInfo.Name));
            }

            var returnParameterAttribute = returnParameterInfo.GetCustomAttribute <ParameterAttribute>();
            //var returnTypeAttributes = methodInfo.GetCustomAttributes<ResultTypeAttribute>();
            IEnumerable <EdmType> modelReturnParameterEdmTypes;

            if (functionAttribute.Type == FunctionType.StoredProcedure)
            {
                if (returnParameterAttribute != null)
                {
                    throw new NotSupportedException(string.Format("ParameterAttribute for method {0} is not supported.", methodInfo.Name));
                }

                modelReturnParameterEdmTypes =
                    GetStoredProcedureReturnTypes(methodInfo)
                    .Select(clrType => GetModelStructualType(model, clrType, methodInfo));
            }
            else
            {
                //if (returnTypeAttributes.Length > 0)
                //{
                //	throw new NotSupportedException(
                //		string.Format("ResultTypeAttribute for method {0} is not supported.", methodInfo.Name));
                //}

                if (functionAttribute.Type == FunctionType.TableValuedFunction)
                {
                    // returnParameterInfo.ParameterType is IQueryable<T>.
                    Type           returnParameterClrType             = returnParameterInfo.ParameterType.GetGenericArguments().Single();
                    StructuralType modelReturnParameterStructuralType = GetModelStructualType(model, returnParameterClrType, methodInfo);
                    modelReturnParameterEdmTypes = Enumerable.Repeat(modelReturnParameterStructuralType, 1);
                }
                else
                {
                    Type returnParameterClrType          = returnParameterInfo.ParameterType;
                    Type returnParameterAttributeClrType = (returnParameterAttribute != null ? returnParameterAttribute.ClrType : null);
                    if (returnParameterAttributeClrType != null && returnParameterAttributeClrType != returnParameterClrType)
                    {
                        throw new NotSupportedException(
                                  string.Format("Return parameter of method {0} is of {1}, but its ParameterAttribute.ClrType has a different type {2}",
                                                methodInfo.Name, returnParameterClrType.FullName, returnParameterAttributeClrType.FullName));
                    }

                    PrimitiveType returnParameterPrimitiveType = GetModelPrimitiveType(model, returnParameterClrType, methodInfo);
                    modelReturnParameterEdmTypes = Enumerable.Repeat(returnParameterPrimitiveType, 1);
                }
            }

            return(modelReturnParameterEdmTypes
                   .Select((edmType, index) => FunctionParameter.Create(
                               string.Format("ReturnType{0}", index),
                               edmType.GetCollectionType(),
                               ParameterMode.ReturnValue))
                   .ToArray());
        }
        private static PrimitiveType GetStoreParameterPrimitiveType(DbModel model, MethodInfo methodInfo, ParameterInfo parameterInfo, FunctionAttribute functionAttribute)
        {
            var parameterClrType = parameterInfo.ParameterType;

            if (parameterClrType.IsByRef)
            {
                parameterClrType = parameterClrType.GetElementType();
            }
            var parameterAttribute = parameterInfo.GetCustomAttribute <ParameterAttribute>();

            //var parameterAttributeClrType = (parameterAttribute != null ? parameterAttribute.ClrType : null);
            if (parameterAttribute != null && parameterAttribute.ClrType != null)
            {
                parameterClrType = parameterAttribute.ClrType;
            }

            //if (parameterClrType.IsGenericType)
            //{
            //	var parameterClrTypeDefinition = parameterClrType.GetGenericTypeDefinition();
            //	if (parameterClrTypeDefinition == typeof(IEnumerable<>) || parameterClrTypeDefinition == typeof(IQueryable<>))
            //	{
            //		//if (functionAttribute.Type == FunctionType.AggregateFunction)
            //		//	parameterClrType = parameterClrType.GetGenericArguments().Single();
            //		//else
            //		throw new NotSupportedException(
            //			string.Format("Parameter {0} of method {1} is not supported. {2} parameter must be used for FunctionType.AggregateFunction method.",
            //				parameterInfo.Name, methodInfo.Name, typeof(IEnumerable<>).FullName));
            //	}
            //}

            //if (parameterClrType == typeof(ObjectParameter))
            //{
            //	// ObjectParameter must be used for stored procedure parameter.
            //	if (functionAttribute.Type != FunctionType.StoredProcedure)
            //	{
            //		throw new NotSupportedException(
            //			string.Format("Parameter {0} of method {1} is not supported. ObjectParameter parameter must be used for FunctionType.StoredProcedure method.",
            //				parameterInfo.Name, methodInfo.Name));
            //	}

            //	// ObjectParameter.Type is available only when methodInfo is called.
            //	// When building model, its store type/clr type must be provided by ParameterAttribute.
            //	if (parameterAttributeClrType == null)
            //	{
            //		throw new NotSupportedException(
            //			string.Format("Parameter {0} of method {1} is not supported. ObjectParameter parameter must have ParameterAttribute with ClrType specified, with optional DbType.",
            //				parameterInfo.Name, methodInfo.Name));
            //	}

            //	parameterClrType = parameterAttributeClrType;
            //}
            //else
            //{
            //	// When parameter is not ObjectParameter, ParameterAttribute.ClrType should be either not specified, or the same as parameterClrType.
            //	if (parameterAttributeClrType != null && parameterAttributeClrType != parameterClrType)
            //	{
            //		throw new NotSupportedException(
            //			string.Format("Parameter {0} of method {1} is not supported. It is of {2} type, but its ParameterAttribute.ClrType has a different type {3}",
            //				parameterInfo.Name, methodInfo.Name, parameterClrType.FullName, parameterAttributeClrType.FullName));
            //	}
            //}


            var storePrimitiveTypeName = (parameterAttribute != null ? parameterAttribute.DbType : null);

            return(!string.IsNullOrEmpty(storePrimitiveTypeName)
                                ? GetStorePrimitiveType(model, storePrimitiveTypeName, methodInfo, parameterInfo)
                                : GetStorePrimitiveType(model, parameterClrType, methodInfo, parameterInfo));
        }
        private static IList <EntitySet> GetModelEntitySets(DbModel model, MethodInfo methodInfo, FunctionAttribute functionAttribute)
        {
            ParameterInfo returnParameterInfo = methodInfo.ReturnParameter;

            if (returnParameterInfo == null || (returnParameterInfo.ParameterType == typeof(void) && functionAttribute.Type != FunctionType.StoredProcedure))
            {
                throw new NotSupportedException(string.Format("The return parameter type of {0} is not supported.", methodInfo.Name));
            }

            if (returnParameterInfo.ParameterType == typeof(void))
            {
                return(new EntitySet[0]);
            }
            else if (functionAttribute.Type == FunctionType.StoredProcedure && returnParameterInfo.ParameterType != typeof(void))
            {
                //// returnParameterInfo.ParameterType is ObjectResult<T>.
                //var returnParameterClrTypes = GetStoredProcedureReturnTypes(methodInfo).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 =>
                //	{
                //		var modelEntitySet = model
                //			.ConceptualModel
                //			.Container
                //			.EntitySets
                //			.FirstOrDefault(entitySet => entitySet.ElementType == GetModelEntityType(model, clrType, methodInfo)); // TODO: bug.

                //		//if (modelEntitySet == null)
                //		//	throw new NotSupportedException(
                //		//		string.Format("{0} for method {1} is not supported in conceptual model as entity set.", clrType.FullName, methodInfo.Name));

                //		return modelEntitySet;

                //	}).Where(s=>s!=null).ToArray();
                //}
            }
            else if (functionAttribute.Type == FunctionType.TableValuedFunction)
            {
                // returnParameterInfo.ParameterType is IQueryable<T>.
                var returnParameterClrType    = returnParameterInfo.ParameterType.GetGenericArguments().Single();
                var returnParameterEntityType = GetModelEntityType(model, returnParameterClrType, methodInfo);
                if (returnParameterEntityType != null)
                {
                    var modelEntitySet = model
                                         .ConceptualModel
                                         .Container
                                         .EntitySets
                                         .FirstOrDefault(entitySet => entitySet.ElementType == returnParameterEntityType);
                    if (modelEntitySet == null)
                    {
                        throw new NotSupportedException(
                                  string.Format("{0} for method {1} is not supported in conceptual model as entity set.",
                                                returnParameterInfo.ParameterType.FullName, methodInfo.Name));
                    }

                    return(new[] { modelEntitySet });
                }
            }

            // Do not return new EntitySet[0], which causes a ArgumentException:
            // The number of entity sets should match the number of return parameters.
            return(null);
        }