public string GetFunctionSignature(string modelName, FunctionDef functionDef, Dictionary <string, string> namespaceTagMap) { string code = ""; if (functionDef.UsesResult) { code = modelName + "." + functionDef.FunctionName + "Result"; } else { if (functionDef.ReturnTypeCode != null) { if (functionDef.ReturnTypeNamespace != null) { code = namespaceTagMap[functionDef.ReturnTypeNamespace] + "."; } code += functionDef.ReturnTypeCode; } else { code = "void"; } } if (functionDef.OutputsList) { code = "List<" + code + ">"; } return(code + " " + functionDef.FunctionName + "(SqlConnection conn,\n\t\t\t\t\t\tSqlTransaction trans"); }
public void AddCommandParameters(StringBuilder buildText, FunctionDef functionDef) { foreach (ParameterDef parameterDef in functionDef.ProcedureDef.ParameterDefMap.Values) { ArgumentDef argumentDef = parameterDef.ArgumentDef; if (parameterDef.IsOutParameter == true) { buildText.AppendLine("\t\t\t\t\tvar outParameter = new " + this.GetSqlParameterText() + " { ParameterName = \"" + parameterDef.ParameterName + "\", Direction = ParameterDirection.Output, Size = " + parameterDef.ParameterSize + ", " + this.GetSqlDbTypeText() + " = " + this.GetSqlDbTypeText() + "." + GetSqlDbTypeCode(parameterDef.ParameterDataTypeCode) + " };"); buildText.AppendLine("\t\t\t\t\tcommand.Parameters.Add(outParameter);"); } else { buildText.Append("\t\t\t\t\tcommand.Parameters.Add(new " + this.GetSqlParameterText() + "(\"" + parameterDef.ParameterName + "\", "); // buildText.Append("(object) " + argumentDef.ArgumentName + " ?? DBNull.Value"); // if (parameterDef.IsNullable == true) { if (argumentDef.IsNullable == true) { buildText.Append("(object) " + argumentDef.ArgumentName + " ?? DBNull.Value"); } else { buildText.Append(argumentDef.ArgumentName); } buildText.AppendLine("));"); } } }
public void CreateFunctionNoRows(StringBuilder buildText, StringBuilder internalInterfaceText, ModelDef modelDef, List <ModelDef> modelDefList, FunctionDef functionDef, Dictionary <string, string> namespaceTagMap) { /* version using all arguments */ string functionString = GetFunctionSignature(modelDef.ModelName, functionDef, namespaceTagMap); string argumentsString = GetArguments(functionDef); string functionSignature = functionString + argumentsString + ")"; internalInterfaceText.AppendLine("\t\t\t" + functionSignature + ";"); internalInterfaceText.AppendLine(); buildText.Append("\t\t\tpublic " + functionSignature + " {"); AddUsingCommand(buildText, functionDef.ProcedureDef); AddCommandParameters(buildText, functionDef); buildText.AppendLine(""); buildText.AppendLine("\t\t\t\t\tcommand.ExecuteNonQuery();"); if (functionDef.ReturnTypeCode != null) { buildText.Append("\t\t\t\t\treturn ("); if (functionDef.ReturnTypeNamespace != null) { buildText.Append(namespaceTagMap[functionDef.ReturnTypeNamespace] + "."); } buildText.AppendLine(functionDef.ReturnTypeCode + ")outParameter.Value;"); } buildText.AppendLine("\t\t\t\t}"); buildText.AppendLine("\t\t\t}"); buildText.AppendLine(""); /* version using object as input */ if (functionDef.ArgumentDefList.Any(x => x.PropertyDef != null)) { string functionSignatureWithObject = functionString + GetObjectArgument(modelDef, namespaceTagMap) + GetArgumentsNotInObject(functionDef) + ")"; internalInterfaceText.AppendLine("\t\t\t" + functionSignatureWithObject + ";"); internalInterfaceText.AppendLine(); buildText.AppendLine("\t\t\tpublic " + functionSignatureWithObject + " {"); buildText.Append("\t\t\t\t"); // buildText.AppendLine($"var actionObject = new {modelDef.ModelName}();"); buildText.Append("\t\t\t\t"); if (functionDef.ReturnTypeCode != null) { buildText.Append("return "); } buildText.AppendLine("this." + functionDef.FunctionName + "(conn, trans,"); AddFunctionArguments(buildText, modelDef, modelDefList, functionDef); buildText.AppendLine("\t\t\t}"); } }
public void CreateFunctionSingleRow(StringBuilder buildText, StringBuilder internalInterfaceText, ModelDef modelDef, List <ModelDef> modelDefList, FunctionDef functionDef, Dictionary <string, string> namespaceTagMap) { string functionString = GetFunctionSignature(modelDef.ModelName, functionDef, namespaceTagMap); string newObjectString = GetNewObjectFunctionArguments(namespaceTagMap, modelDef, modelDefList); string argumentsString = GetArguments(functionDef); string functionSignature = functionString + newObjectString + argumentsString + ")"; internalInterfaceText.AppendLine("\t\t\t" + functionSignature + ";"); internalInterfaceText.AppendLine(); buildText.AppendLine("\t\t\tpublic " + functionSignature + " {"); AddUsingCommand(buildText, functionDef.ProcedureDef); AddCommandParameters(buildText, functionDef); buildText.AppendLine("\t\t\t\t\tusing (var reader = command.ExecuteReader()) {"); buildText.AppendLine("\t\t\t\t\t\tif (reader.Read()) {"); if (functionDef.UsesResult) { AddExtraResultFill(buildText, modelDef, modelDefList, functionDef, namespaceTagMap); buildText.AppendLine("\t\t\t\t\t\t\treturn item;"); } else { buildText.Append("\t\t\t\t\t\t\treturn MakeObject(reader"); AddMakeObjectCallFunctionArguments(buildText, namespaceTagMap, modelDef, modelDefList); buildText.AppendLine(", null);"); } buildText.AppendLine("\t\t\t\t\t\t} else {"); buildText.AppendLine("\t\t\t\t\t\t\treturn null;"); buildText.AppendLine("\t\t\t\t\t\t}"); buildText.AppendLine("\t\t\t\t\t}"); buildText.AppendLine("\t\t\t\t}"); buildText.AppendLine("\t\t\t}"); buildText.AppendLine(""); /* Only use the Object input version if there are fields that come from the object */ if (functionDef.ArgumentDefList.Any(x => x.PropertyDef != null)) { string functionSignatureWithObject = functionString + newObjectString + GetObjectArgument(modelDef, namespaceTagMap) + GetArgumentsNotInObject(functionDef) + ")"; internalInterfaceText.AppendLine("\t\t\t" + functionSignatureWithObject + ";"); internalInterfaceText.AppendLine(); buildText.Append("\t\t\tpublic " + functionSignatureWithObject + " {"); buildText.AppendLine("\t\t\t\treturn this." + functionDef.FunctionName + "(conn, trans"); AddMakeObjectCallFunctionArguments(buildText, namespaceTagMap, modelDef, modelDefList); buildText.AppendLine(","); AddFunctionArguments(buildText, modelDef, modelDefList, functionDef); buildText.AppendLine("\t\t\t}"); } }
public string GetArgumentsNotInObject(FunctionDef functionDef) { StringBuilder buildText = new StringBuilder(); foreach (ArgumentDef argumentDef in functionDef.ArgumentDefList) { if (argumentDef.PropertyDef == null) { buildText.AppendLine(","); buildText.Append("\t\t\t\t\t\t" + argumentDef.ArgumentTypeCode + (argumentDef.IsNullable ? "?" : "") + " " + argumentDef.ArgumentName); } } return(buildText.ToString()); }
public string GetArguments(FunctionDef functionDef) { StringBuilder buildText = new StringBuilder(); foreach (ArgumentDef argumentDef in functionDef.ArgumentDefList) { buildText.AppendLine(","); bool isNullable = argumentDef.IsNullable; //if (argumentDef.PropertyDef != null) { // if (argumentDef.PropertyDef.PropertyTypeCode.EndsWith("?")) { // if (isNullable == false) { // Shared.Warning($"Remapping argument {argumentDef.ArgumentName} to nullable based on corresponding propertydef with type {argumentDef.PropertyDef.PropertyTypeCode}."); // isNullable = true; // } // } //} buildText.Append("\t\t\t\t\t\t" + OutputNullableType(argumentDef.ArgumentTypeCode, argumentDef.IsNullable) + " " + argumentDef.ArgumentName); } return(buildText.ToString()); }
public void CreateFunctionMultiRow(StringBuilder buildText, StringBuilder internalInterfaceText, ModelDef modelDef, List <ModelDef> modelDefList, FunctionDef functionDef, Dictionary <string, string> namespaceTagMap) { string functionString = GetFunctionSignature(modelDef.ModelName, functionDef, namespaceTagMap); string newObjectString = GetNewObjectFunctionArguments(namespaceTagMap, modelDef, modelDefList); string argumentsString = GetArguments(functionDef); string functionSignature = functionString + newObjectString + argumentsString + ")"; internalInterfaceText.AppendLine("\t\t\t" + functionSignature + ";"); internalInterfaceText.AppendLine(); buildText.AppendLine("\t\t\tpublic " + functionSignature + " {"); AddUsingCommand(buildText, functionDef.ProcedureDef); AddCommandParameters(buildText, functionDef); if (functionDef.UsesResult == true) { buildText.AppendLine("\t\t\t\t\tvar list = new List<" + functionDef.FunctionName + "Result>();"); buildText.AppendLine("\t\t\t\t\tusing (var reader = command.ExecuteReader()) {"); buildText.AppendLine("\t\t\t\t\t\twhile (reader.Read()) {"); AddExtraResultFill(buildText, modelDef, modelDefList, functionDef, namespaceTagMap); buildText.AppendLine("\t\t\t\t\t\t\tlist.Add(item);"); buildText.AppendLine("\t\t\t\t\t\t}"); buildText.AppendLine("\t\t\t\t\t}"); buildText.AppendLine("\t\t\t\t\treturn list;"); } else { buildText.Append("\t\t\t\t\treturn BuildList(command"); AddMakeObjectCallFunctionArguments(buildText, namespaceTagMap, modelDef, modelDefList); buildText.AppendLine(");"); } buildText.AppendLine("\t\t\t\t}"); buildText.AppendLine("\t\t\t}"); }
public void AddExtraResultFill(StringBuilder buildText, ModelDef modelDef, List <ModelDef> modelDefList, FunctionDef functionDef, Dictionary <string, string> namespaceTagMap) { buildText.AppendLine("\t\t\t\t\t\t\tvar item = new " + functionDef.FunctionName + "Result {"); bool first = true; if (modelDef.IsJustTable == false) { buildText.Append("\t\t\t\t\t\t\t\t\t" + modelDef.ModelName + " = MakeObject(reader"); AddMakeObjectCallFunctionArguments(buildText, namespaceTagMap, modelDef, modelDefList); buildText.Append(", null)"); first = false; } foreach (var resultPropertyDef in functionDef.ResultPropertyDefList) { if (first == true) { first = false; } else { buildText.AppendLine(","); } var fieldDef = resultPropertyDef.FieldDef; buildText.Append("\t\t\t\t\t\t\t\t\t" + resultPropertyDef.PropertyName + " = "); if (fieldDef.IsNullable && resultPropertyDef.PropertyTypeCode != "string") { OutputUnNull(buildText, resultPropertyDef.PropertyTypeCode, "reader[\"" + fieldDef.FieldName + "\"]"); } else { buildText.Append("(" + resultPropertyDef.PropertyTypeCode + ")reader[\"" + fieldDef.FieldName + "\"]"); } } buildText.AppendLine("};"); }
public void AddFunctionArguments(StringBuilder buildText, ModelDef modelDef, List <ModelDef> modelDefList, FunctionDef functionDef) { bool firstParameter = true; foreach (ArgumentDef argumentDef in functionDef.ArgumentDefList) { if (firstParameter) { firstParameter = false; } else { buildText.AppendLine(","); } buildText.Append("\t\t\t\t\t\t"); PropertyDef propertyDef = argumentDef.PropertyDef; if (propertyDef == null) { /* display a friendly warning if the field might be missing in the target class */ if (argumentDef.ArgumentName.EndsWith("Key", false, CultureInfo.InvariantCulture)) { Shared.Warning("Argument " + argumentDef.ArgumentName + " in function " + functionDef.FunctionName + " for " + functionDef.ProcedureDef.ProcedureName + " could not be found as a property of the model. Perhaps a foreign key reference doesn't exist on that column of the database table?"); } else { Shared.Warning("Argument " + argumentDef.ArgumentName + " in function " + functionDef.FunctionName + " for " + functionDef.ProcedureDef.ProcedureName + " could not be found as a property of the model. This is normal when the stored procedure uses this field within the procedure as an external value that lives outside the table. If not, please verify:" + Environment.NewLine + "\t\tShould the column exist in the model class but is missing?" + Environment.NewLine + "\t\tPerhaps it is spelled differently and needs an entry in the mapping file referenced by --namemapfile?"); } buildText.Append(argumentDef.ArgumentName); } else { if (propertyDef.IsReference) { string subPropertyName = propertyDef.PropertyName; if (argumentDef.ArgumentName.EndsWith("Key", false, CultureInfo.InvariantCulture)) { /* TODO: this is failing when type is an interface */ var referencedModelDef = propertyDef.GetModelDef(modelDefList); var idPropertyName = propertyDef.PropertyTypeCode + "ID"; var idPropertyDef = referencedModelDef.PropertyDefMap[idPropertyName]; var idTypeCode = idPropertyDef.PropertyTypeCode; // buildText.Append($"/* {idPropertyName}, {idPropertyDef}, {idTypeCode}"); if (idTypeCode.EndsWith("?")) { subPropertyName = idPropertyName + ".Value"; } else { subPropertyName = idPropertyName; } } if (argumentDef.IsNullable) { // buildText.Append("(inputObject." + propertyDef.PropertyName + " == null) ? (" + argumentDef.ArgumentTypeCode + "?)null : inputObject." + propertyDef.PropertyName + "." + subPropertyName); buildText.Append("inputObject." + propertyDef.PropertyName + "?." + subPropertyName); } else { buildText.Append("inputObject." + propertyDef.PropertyName + "." + subPropertyName); } } else { buildText.Append("inputObject." + propertyDef.PropertyName); if (propertyDef.IsEnum) { buildText.Append(".ToString()"); } } } } buildText.AppendLine(");"); }
public static List <ModelDef> CreateModelDefList(string modelNamespace, string moduleName, Dictionary <string, ModelDef> modelDefMap, List <ProcedureDef> procedureDefList, List <string> ignoreTableNameList, List <TableMapping> tableMappingList, bool cleanOracle) { // List<ModelDef> modelDefList = new List<ModelDef>(); foreach (ProcedureDef procedureDef in procedureDefList) { string procedureName = procedureDef.ProcedureName; int firstUnderscoreIndex = procedureName.IndexOf('_'); int secondUnderscoreIndex = procedureName.IndexOf('_', firstUnderscoreIndex + 1); // int lastUnderscoreIndex = procedureName.LastIndexOf('_'); // string modelName = procedureName.Substring(firstUnderscoreIndex + 1, lastUnderscoreIndex - firstUnderscoreIndex - 1); // string functionName = procedureName.Substring(lastUnderscoreIndex + 1); /* This assumes that no tables have underscores in their names */ /* TODO: probably need an table name underscore removal method elsewhere. */ string modelName = procedureName.Substring(firstUnderscoreIndex + 1, secondUnderscoreIndex - firstUnderscoreIndex - 1); string functionName = procedureName.Substring(secondUnderscoreIndex + 1); /* skip tables we are ignoring */ if (ignoreTableNameList.Contains(modelName)) { continue; } ModelDef modelDef = null; if (modelDefMap.ContainsKey(modelName)) { modelDef = modelDefMap[modelName]; } else { Shared.Info("Adding a virtual model after table named " + modelName + " from procedure " + procedureName + " which did not have a matching model in the models collection."); modelDef = new ModelDef { ModelName = modelName, FieldDefMap = new Dictionary <string, FieldDef>(), FunctionDefList = new List <FunctionDef>(), Namespace = "", PropertyDefMap = new Dictionary <string, PropertyDef>(), UsesBuildListFunction = false, UsesMakeObjectFunction = false, IsJustTable = true }; modelDefMap[modelName] = modelDef; } FunctionDef functionDef = new FunctionDef { FunctionName = functionName, ProcedureDef = procedureDef, ArgumentDefList = new List <ArgumentDef>() }; modelDef.FunctionDefList.Add(functionDef); bool isSingleRow = (functionName.StartsWith("Read")); if (procedureDef.OutputsRows == true) { functionDef.OutputsList = true; modelDef.UsesMakeObjectFunction = true; functionDef.ReturnTypeCode = modelDef.ModelName; functionDef.ReturnTypeNamespace = modelDef.Namespace; if (isSingleRow == true) { functionDef.OutputsList = false; functionDef.OutputsObject = true; } else { functionDef.OutputsList = true; functionDef.OutputsObject = false; modelDef.UsesBuildListFunction = true; } } else { functionDef.OutputsList = false; functionDef.OutputsObject = false; } foreach (ParameterDef parameterDef in procedureDef.ParameterDefMap.Values) { string typeCode = TypeConvertor.ConvertNullableSQLToCSharp(parameterDef.ParameterDataTypeCode, parameterDef.IsNullable); if (parameterDef.IsOutParameter == true) { if (functionDef.ReturnTypeCode != null) { throw new ApplicationException("Stored procedure " + procedureDef.ProcedureName + " returns row data but also has an out parameter: " + parameterDef.ParameterName); } functionDef.ReturnTypeCode = typeCode; functionDef.ReturnTypeNamespace = null; } else { bool isNullable = false; if (typeCode != "string") { if (parameterDef.ColumnDef != null) { if (parameterDef.ColumnDef.IsNullable == true) { isNullable = true; } } else { /* if we don't know, we are going to allow them */ isNullable = true; } } ArgumentDef argumentDef = new ArgumentDef { ArgumentName = Char.ToLowerInvariant(parameterDef.ParameterName[1]) + parameterDef.ParameterName.Substring(2), ArgumentTypeCode = typeCode, ParameterDef = parameterDef, IsNullable = isNullable }; parameterDef.ArgumentDef = argumentDef; string parameterName = parameterDef.ParameterName; PropertyDef propertyDef = modelDef.GetLikelyPropertyDef(parameterDef.ParameterName.Substring(1)); if (propertyDef != null) { argumentDef.PropertyDef = propertyDef; parameterDef.PropertyDef = propertyDef; // Shared.Info($"DEBUG: Found propertyDef of {propertyDef.PropertyName} for parameterName:{parameterDef.ParameterName} in function {functionName}."); /* TODO: seems like there should be a better way of storing isNullable at the property level */ /* we can't know from the models property type if strings are nullable or not so we just always assume they are */ if (propertyDef.PropertyTypeCode.EndsWith("?") == true || propertyDef.PropertyTypeCode == "string") { argumentDef.IsNullable = true; parameterDef.IsNullable = true; } } else { Shared.Info($"Warning: Could not find a propertyDef for parameterName:{parameterDef.ParameterName} in function {functionName} of {modelName}.."); } functionDef.ArgumentDefList.Add(argumentDef); } } if (procedureDef.OutputsRows == true) { functionDef.OutputPropertyDefList = new List <PropertyDef>(); foreach (FieldDef fieldDef in procedureDef.FieldDefMap.Values) { string fieldName = fieldDef.FieldName; string convertedFieldName = NameMapping.MakeCleanColumnName(tableMappingList, fieldDef.BaseTableName, modelDef.ModelName, fieldName, cleanOracle); PropertyDef propertyDef = modelDef.GetLikelyPropertyDef(convertedFieldName); /* We can easily get a field that is several layers back from our root object from joins * in the query. * for example Book.Author.City.State.Country.CountryName, and the query returns CountryName. * We need to work down through the object graph to find the model that matches the table * which that field is using. * It may be that in the initial procedure read when we query the first recordset, with a browse value that * returns join columns, that we can use that information to traverse the model tree more * directly. */ List <PropertyDef> propertyDefChain = null; if (propertyDef == null) { var referencedModelName = NameMapping.MakeCleanTableName(tableMappingList, fieldDef.BaseTableName, cleanOracle); // Shared.Info($"DEBUG:convertedFieldName:{convertedFieldName}, fieldDef.BaseTableName={fieldDef.BaseTableName}, referencedModelName={referencedModelName}"); if (modelDefMap.ContainsKey(referencedModelName) == true) { var referencedModelDef = modelDefMap[referencedModelName]; var usedModelDefList = new List <ModelDef>() { modelDef }; propertyDefChain = modelDef.ScanForLikelyPropertyDef(new List <PropertyDef>(), convertedFieldName, referencedModelDef, modelDefMap.Values.ToList <ModelDef>(), usedModelDefList); if (propertyDefChain != null) { //Shared.Info($"DEBUG: Found propertydef chain! fieldName:{convertedFieldName} in procedure {procedureDef.ProcedureName}"); //propertyDefChain.ForEach(x => { // Shared.Info($"{x.PropertyTypeNamespace}.{x.PropertyTypeCode} {x.PropertyName}"); //}); } } } /* if we didn't find a propertydef nor a propertydefchain, then it belongs as part of a function-specific Result output */ if (propertyDef == null && propertyDefChain == null) { if (functionDef.UsesResult == false) { functionDef.UsesResult = true; functionDef.ResultPropertyDefList = new List <ResultPropertyDef>(); } functionDef.ResultPropertyDefList.Add(new ResultPropertyDef { PropertyName = CleanPropertyName(convertedFieldName), PropertyTypeCode = fieldDef.DataTypeCode, FieldDef = fieldDef }); Shared.Info($"Warning: Could not find a propertyDef for fieldName \"{convertedFieldName}\" in procedure \"{procedureDef.ProcedureName}\". " + $"The base table name for this field at the SQL level was \"{fieldDef.BaseTableName}\". " + $"The converted model name was computed as \"{NameMapping.MakeCleanTableName(tableMappingList, fieldDef.BaseTableName, cleanOracle)}\". " + $"This field will be included as a property in a result class labeled \"{functionDef.FunctionName}Result\" created just for the output of this function."); } /* TODO: Commented the type check because it couldn't resolve object v. key value. May not be necessary really. * /* * * string propertyTypeCode = TypeConvertor.ConvertNullableSQLToCSharp(fieldDef.DataTypeCode, fieldDef.IsNullable); * * if (propertyDef.PropertyTypeCode != propertyTypeCode) { * throw new ApplicationException("PropertyTypeCode for " + modelDef.ModelName + "." + propertyDef.PropertyName + " found " + propertyDef.PropertyTypeCode + " but wanted " + propertyTypeCode + " based on field " + fieldDef.FieldName + " with data type " + fieldDef.DataTypeCode + " and IsNullable=" + fieldDef.IsNullable); * } */ // propertyDef.FieldDefList.Add(fieldDef); fieldDef.PropertyDef = propertyDef; fieldDef.PropertyDefChain = propertyDefChain; functionDef.OutputPropertyDefList.Add(propertyDef); if (modelDef.FieldDefMap.ContainsKey(fieldDef.FieldName)) { FieldDef foundFieldDef = modelDef.FieldDefMap[fieldDef.FieldName]; if (foundFieldDef.BaseTableName != fieldDef.BaseTableName) { throw new ApplicationException("A stored procedure (" + procedureDef.ProcedureName + ") based on model " + modelDef.ModelName + " returned a field pointing to a base table named " + fieldDef.BaseTableName + ", but another procedure (" + foundFieldDef.ProcedureDef.ProcedureName + " had produced a field with the same name based on table " + foundFieldDef.BaseTableName + ". Consider using two different names for this value in the two procedures."); } } else { modelDef.FieldDefMap[fieldDef.FieldName] = fieldDef; } } } } return(modelDefMap.Values.ToList <ModelDef>()); }