private static PrimitiveType GetModelParameterPrimitiveType( this DbModel model, MethodInfo methodInfo, ParameterInfo parameterInfo) { // <Parameter Name="PersonID" Mode="In" Type="Int32" /> Type parameterClrType = parameterInfo.ParameterType; ParameterAttribute parameterAttribute = parameterInfo.GetCustomAttribute <ParameterAttribute>(); Type parameterAttributeClrType = parameterAttribute?.ClrType; if (parameterClrType == typeof(ObjectParameter)) { // 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( $"Parameter {parameterInfo.Name} of method {methodInfo.Name} is not supported. {nameof(ObjectParameter)} parameter must have {nameof(ParameterAttribute)} with {nameof(ParameterAttribute.ClrType)} specified."); } parameterClrType = parameterAttributeClrType; } else { // When parameter is not ObjectParameter, ParameterAttribute.ClrType should be the same as parameterClrType, or not specified. if (parameterAttributeClrType != null && parameterAttributeClrType != parameterClrType) { throw new NotSupportedException( $"Parameter {parameterInfo.Name} of method {methodInfo.Name} if of {parameterClrType.FullName}, but its {nameof(ParameterAttribute)}.{nameof(ParameterAttribute.ClrType)} has a different type {parameterAttributeClrType.FullName}"); } } return(model.GetModelPrimitiveType(parameterClrType, methodInfo)); }
private static string GetStoreCommandText(this MethodInfo methodInfo, FunctionAttribute functionAttribute, string functionName) { if (functionAttribute.Type == FunctionType.NonComposableScalarValuedFunction) { string schema = functionAttribute.Schema; schema = string.IsNullOrWhiteSpace(schema) ? string.Empty : $"[{schema}]."; IEnumerable <string> parameterNames = methodInfo .GetParameters() .Select(parameterInfo => { ParameterAttribute parameterAttribute = parameterInfo.GetCustomAttribute <ParameterAttribute>(); string parameterName = parameterAttribute?.Name; return(string.IsNullOrWhiteSpace(parameterName) ? parameterInfo.Name : parameterName); }) .Select(parameterName => $"@{parameterName}"); return($"SELECT {schema}[{functionName}]({string.Join(", ", parameterNames)})"); } 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 different type {returnParameterAttributeClrType.FullName}"); } PrimitiveType returnParameterPrimitiveType = model.GetModelPrimitiveType(returnParameterClrType, methodInfo); modelReturnParameterEdmTypes = Enumerable.Repeat(returnParameterPrimitiveType, 1); } } return(modelReturnParameterEdmTypes .Select((edmType, index) => FunctionParameter.Create( $"ReturnType{index}", functionAttribute.Type == FunctionType.ModelDefinedFunction ? edmType : edmType.GetCollectionType(), ParameterMode.ReturnValue)) .ToArray()); }
private static IList <FunctionParameter> GetStoreReturnParameters( this DbModel model, MethodInfo methodInfo, FunctionAttribute functionAttribute) { ParameterInfo returnParameterInfo = methodInfo.ReturnParameter; if (returnParameterInfo == null || returnParameterInfo.ParameterType == typeof(void)) { throw new NotSupportedException($"The return type of {methodInfo.Name} is not supported."); } ParameterAttribute returnParameterAttribute = returnParameterInfo.GetCustomAttribute <ParameterAttribute>(); ResultTypeAttribute[] returnTypeAttributes = methodInfo.GetCustomAttributes <ResultTypeAttribute>().ToArray(); if (functionAttribute.Type == FunctionType.StoredProcedure) { if (returnParameterAttribute != null) { throw new NotSupportedException( $"{nameof(ParameterAttribute)} for return value of method {methodInfo.Name} is not supported."); } return(new FunctionParameter[0]); } if (returnTypeAttributes.Any()) { throw new NotSupportedException($"{nameof(ResultTypeAttribute)} for method {methodInfo.Name} is not supported."); } if (functionAttribute.Type == FunctionType.TableValuedFunction) { if (returnParameterAttribute != null) { throw new NotSupportedException( $"{nameof(ParameterAttribute)} for return value of method {methodInfo.Name} is not supported."); } /* * <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>. Type storeReturnParameterClrType = returnParameterInfo.ParameterType.GetGenericArguments().Single(); StructuralType modelReturnParameterStructuralType = model.GetModelStructualType( storeReturnParameterClrType, methodInfo); ComplexType modelReturnParameterComplexType = modelReturnParameterStructuralType as ComplexType; RowType storeReturnParameterRowType; if (modelReturnParameterComplexType != null) { storeReturnParameterRowType = RowType.Create( modelReturnParameterComplexType.Properties.Select(property => EdmProperty.Create(property.Name, model.ProviderManifest.GetStoreType(property.TypeUsage))), null); } else { EntityType modelReturnParameterEntityType = modelReturnParameterStructuralType as EntityType; if (modelReturnParameterEntityType != null) { storeReturnParameterRowType = RowType.Create( modelReturnParameterEntityType.Properties.Select(property => { var typeUsage = TypeUsage.Create(model.ProviderManifest.GetStoreType(property.TypeUsage).EdmType, property.TypeUsage.Facets); var result = EdmProperty.Create(property.Name, typeUsage); var propertyNames = new[] { nameof(EdmProperty.Name), nameof(EdmProperty.TypeUsage), nameof(EdmProperty.MetadataProperties) }; result.SetMetadataProperties(property.MetadataProperties.Where(m => !propertyNames.Contains(m.Name))); return(result); }), null); //storeReturnParameterRowType = RowType.Create( // modelReturnParameterEntityType.Properties.Select(property => property.Clone()), // null); } else { throw new NotSupportedException($"Structural type {modelReturnParameterStructuralType.FullName} of method {methodInfo.Name} cannot be converted to {nameof(RowType)}."); } } return(new FunctionParameter[] { 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"> PrimitiveType storeReturnParameterPrimitiveType = model.GetStoreParameterPrimitiveType(methodInfo, returnParameterInfo, functionAttribute); return(new FunctionParameter[] { FunctionParameter.Create("ReturnType", storeReturnParameterPrimitiveType, ParameterMode.ReturnValue) }); }
private static PrimitiveType GetStoreParameterPrimitiveType( this DbModel model, MethodInfo methodInfo, ParameterInfo parameterInfo, FunctionAttribute functionAttribute) { // <Parameter Name="PersonID" Type="int" Mode="In" /> Type parameterClrType = parameterInfo.ParameterType; ParameterAttribute parameterAttribute = parameterInfo.GetCustomAttribute <ParameterAttribute>(); Type parameterAttributeClrType = parameterAttribute?.ClrType; if (parameterClrType.IsGenericType) { Type parameterClrTypeDefinition = parameterClrType.GetGenericTypeDefinition(); if (parameterClrTypeDefinition == typeof(IEnumerable <>) || parameterClrTypeDefinition == typeof(IQueryable <>)) { if (functionAttribute.Type == FunctionType.AggregateFunction) { // Aggregate function has one IEnumerable<T> or IQueryable<T> parameter. parameterClrType = parameterClrType.GetGenericArguments().Single(); } else { throw new NotSupportedException( $"Parameter {parameterInfo.Name} of method {methodInfo.Name} is not supported. {typeof(IEnumerable<>).FullName} parameter must be used for {nameof(FunctionType)}.{nameof(FunctionType.AggregateFunction)} method."); } } } if (parameterClrType == typeof(ObjectParameter)) { // ObjectParameter must be used for stored procedure parameter. if (functionAttribute.Type != FunctionType.StoredProcedure) { throw new NotSupportedException( $"Parameter {parameterInfo.Name} of method {methodInfo.Name} is not supported. {nameof(ObjectParameter)} parameter must be used for {nameof(FunctionType)}.{nameof(FunctionType.StoredProcedure)} method."); } // 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( $"Parameter {parameterInfo.Name} of method {methodInfo.Name} is not supported. {nameof(ObjectParameter)} parameter must have {nameof(ParameterAttribute)} with {nameof(ParameterAttribute.ClrType)} specified, with optional {nameof(ParameterAttribute.DbType)}."); } 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( $"Parameter {parameterInfo.Name} of method {methodInfo.Name} is not supported. It is of {parameterClrType.FullName} type, but its {nameof(ParameterAttribute)}.{nameof(ParameterAttribute.ClrType)} has a different type {parameterAttributeClrType.FullName}"); } } string storePrimitiveTypeName = parameterAttribute?.DbType; return(!string.IsNullOrEmpty(storePrimitiveTypeName) ? model.GetStorePrimitiveType(storePrimitiveTypeName, methodInfo, parameterInfo) : model.GetStorePrimitiveType(parameterClrType, methodInfo, parameterInfo)); }