Files
Common-VS2019/SacsStandardDbas/Dbas/Base/DatabaseDefinitionGenerator.cs
T
2025-02-08 16:41:25 +00:00

882 lines
48 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.IO;
using Sarand.Net.Standard.Base.Utils;
namespace Sarand.Net.Standard.Dbas.Base
{
//=======================================================================
public class DatabaseDefinitionGenerator
{
//-------------------------------------------------------------------
// Configuration.
public enum SarandCommonVersion
{
VS2017,
/// <summary>
/// Visual Studio 2019 version. StringListUtil rather than StringList.
/// </summary>
VS2019
}
public enum DotNetVersion
{
Framework,
Core3,
}
public enum Dbms
{
ODBC,
SQL,
}
public enum DefinitionOutput
{
DatabaseSchema,
DatabaseDefinitionClass,
TableInterfaceClasses
}
public class Config
{
public SarandCommonVersion SarandCommonVersion { get; set; } = SarandCommonVersion.VS2019;
public DotNetVersion DotNetVersion { get; set; } = DotNetVersion.Framework;
public SacsDatabase Database { get; set; }
public Dbms DbmsOutput { get; set; } = Dbms.ODBC;
public String OutputDirectory { get; set; } = "";
public bool ConfirmDirectoryClear { get; set; } = true;
// Database schema.
public class SchemaData
{
// Tables to be included (all others excluded) or those to be excluded.
public HashSet<String> Tables_Included { get; } = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
public HashSet<String> Tables_Excluded { get; } = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
public HashSet<String> Tables_ExcludedFromDatabaseSchema { get; } = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
public HashSet<String> Tables_ExcludedFromDatabaseDefinitionClass { get; } = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
public HashSet<String> Tables_ExcludedFromTableInterfaceClasses { get; } = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
// Schema capitalisation - for class name prefix etc - where capitalising first letter is insufficient.
public Dictionary<String, String> SchemaNameCapitalisation { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
// Alternative table names.
public Dictionary<String, List<String>> AlternativeTableNames { get; } = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
public void AddAlternativeTableName(String tableName, String tableNameAlternative)
{
if (!AlternativeTableNames.ContainsKey(tableName)) AlternativeTableNames[tableName] = new List<string>();
AlternativeTableNames[tableName].Add(tableNameAlternative);
}
// Insert only columns - not modified on update:
// Table name - regular expressions allowed.
// Comma separated list of columns
// eg. New StringPair(".*","CreateOn,CreateBy");
public List<StringPair> InsertOnlyColumns { get; } = new List<StringPair>();
}
public SchemaData Schema { get; } = new SchemaData();
// Database definition class.
public class DefinitionClassConfig
{
/// <summary>Using namespaces for database definition and table class usings.</summary>
public HashSet<String> Usings { get; } = new HashSet<String>() { "Sarand.Net.Standard.Base.Core", "Sarand.Net.Standard.Base.Dbas" };
public String Namespace { get; set; } = "Sarand.Application.Core.Base";
public String Classname { get; set; } = "SaDbDfn";
}
public DefinitionClassConfig DefinitionClass { get; } = new DefinitionClassConfig();
// Table class.
public class TableClassConfig
{
/// <summary>Using namespaces for table classes.</summary>
public HashSet<String> Usings { get; } = new HashSet<String>() { "Sarand.Net.Standard.Base.App", "Sarand.Net.Standard.Base.Core", "Sarand.Net.Standard.Base.Dbas" };
public String Namespace_BaseClass { get; set; } = "Sarand.Net.Standard.Dbas.Data";
public String Namespace { get; set; } = "Sarand.Application.Dbas";
public String BaseClass { get; set; } = "DbDataItem";
public String ClassName_DatabaseInfo = "IDbDataItem.IDatabaseInfo";
public bool MandatoryConstructorDbInfo = false;
public bool TreatDoubleFormatAsDecimal { get; set; } = false;
}
public TableClassConfig TableClass { get; } = new TableClassConfig();
}
//-------------------------------------------------------------------
// Data members.
private Config config = null;
private const String DefaultSchema_MSSQL = "dbo";
private static String /*lf = "\n",*/ crlf = "\r\n", tab1 = "\t", tab2 = "\t\t", tab3 = "\t\t\t", tab4 = "\t\t\t\t", tab5 = "\t\t\t\t\t";
// Reserved words.
private static readonly String[] reservedWords =
{
"ADD", "ALL", "ALTER", "AND", "ANY", "AS", "ASC", "AVG", "BEGIN", "BETWEEN", "BY", "CASE", "CAST", "COLUMN", "COMMIT", "CONSTRAINT",
"CONVERT", "COUNT", "CREATE", "CURRENCY", "DEFAULT", "DELETE", "DESC", "DISTINCT", "DROP", "ELSE", "END", "EXECUTE", "EXISTS", "FALSE",
"FROM", "GRANT", "GROUP", "HAVING", "IN", "INDEX", "INNER", "INSERT", "INTO", "IS", "JOIN", "KEY", "LEFT", "LIKE", "MAX", "MIN", "NOT",
"NULL", "ON", "OR", "ORDER", "OUTER", "OUTPUT", "PRIMARY", "PROCEDURE", "REVOKE", "ROLLBACK", "ROWCOUNT", "SELECT", "SET", "SQL", "SUM",
"TABLE", "THEN", "TRANSACTION", "TRUE", "UNION", "UNIQUE", "UPDATE", "USER", "VALUES", "VIEW", "WHEN", "WHERE"
};
//-------------------------------------------------------------------
public bool Generate(Config config)
{
// Validate configuration.
this.config = config;
if (!FileUtil.IsDirectory(config.OutputDirectory))
throw new Exception("Invalid directory specified [" + config.OutputDirectory + "]");
// Validate and cleanse configuration parameters.
if (StringUtil.IsEmpty(StringUtil.TrimAll(config.TableClass.BaseClass)))
config.TableClass.BaseClass = "DbDataItem";
// Clear files from output firectory.
if (Directory.EnumerateFiles(config.OutputDirectory, "*", SearchOption.TopDirectoryOnly).Count() > 0)
{
SaLogger.Info($"{SysUtil.Fn} Deleting existing files in output folders.");
DirectoryInfo di = new DirectoryInfo(config.OutputDirectory);
foreach (FileInfo file in di.EnumerateFiles())
file.Delete();
}
// Table definitions.
List<DbDfnTable> tableDfns = new List<DbDfnTable>(config.Database.GetTableDfns());
// Database schema XML.
GenerateDatabaseSchemaXml(tableDfns.Where(item => IsValidTable(item.Name, DefinitionOutput.DatabaseSchema)));
// Database definition class.
GenerateDatabaseDefinitionClass(tableDfns.Where(item => IsValidTable(item.Name, DefinitionOutput.DatabaseDefinitionClass)));
// Database table Classes.
foreach (DbDfnTable tableDfn in tableDfns.Where(item => IsValidTable(item.Name, DefinitionOutput.TableInterfaceClasses)))
GenerateTableInterfaceClass(tableDfn);
return true;
}
//-------------------------------------------------------------------
private bool IsValidTable(String table, DefinitionOutput output)
{
if (String.IsNullOrEmpty(table)) return false;
if (config.Schema.Tables_Included.Count > 0 && !config.Schema.Tables_Included.ContainsCI(table)) return false;
if (config.Schema.Tables_Excluded.Count > 0 && config.Schema.Tables_Excluded.ContainsCI(table)) return false;
// Tables excluded from specific output.
if (output == DefinitionOutput.DatabaseSchema && config.Schema.Tables_ExcludedFromDatabaseSchema.Contains(table)) return false;
if (output == DefinitionOutput.DatabaseDefinitionClass && config.Schema.Tables_ExcludedFromDatabaseDefinitionClass.Contains(table)) return false;
if (output == DefinitionOutput.TableInterfaceClasses && config.Schema.Tables_ExcludedFromTableInterfaceClasses.Contains(table)) return false;
return true;
}
//-------------------------------------------------------------------
private void GenerateDatabaseSchemaXml(IEnumerable<DbDfnTable> tableDfns)
{
String filePath = config.OutputDirectory + Path.DirectorySeparatorChar + config.DefinitionClass.Classname + ".xml";
// Construct database definition.
DbDfnDatabase databaseDfn = new DbDfnDatabase();
foreach (DbDfnTable tableDfn in tableDfns)
databaseDfn.AddTable(tableDfn);
using (StreamWriter file = new StreamWriter(filePath))
{
file.Write(SerializableUtil.ToXml(databaseDfn));
}
}
//-------------------------------------------------------------------
/// <summary>Intercept column variable type name to replace double/float with decimal where required.</summary>
private String GetColumnVariableTypeName(DbDfnColumn columnDfn)
{
return GetColumnVariableTypeName(columnDfn, config.TableClass.TreatDoubleFormatAsDecimal);
}
/// <summary>Intercept column variable type name to replace double/float with decimal where required.</summary>
private static String GetColumnVariableTypeName(DbDfnColumn columnDfn, bool treatDoubleFormatAsDecimal)
{
String typeName = columnDfn.GetVariableTypeName();
if (treatDoubleFormatAsDecimal)
{
switch (columnDfn.DataType)
{
case DbColumnDataType.Single:
case DbColumnDataType.Double:
typeName = "Decimal";
break;
}
}
return typeName;
}
//-------------------------------------------------------------------
/// <summary>Intercept column variable type to replace double/float with decimal where required.</summary>
private String GetColumnVariableType(DbDfnColumn columnDfn)
{
return GetColumnVariableType(columnDfn, config.TableClass.TreatDoubleFormatAsDecimal);
}
/// <summary>Intercept column variable type to replace double/float with decimal where required.</summary>
private static String GetColumnVariableType(DbDfnColumn columnDfn, bool treatDoubleFormatAsDecimal)
{
String typeName = columnDfn.GetVariableType();
if (treatDoubleFormatAsDecimal)
{
switch (columnDfn.DataType)
{
case DbColumnDataType.Single:
case DbColumnDataType.Double:
typeName = "Decimal";
break;
}
}
return typeName;
}
//-------------------------------------------------------------------
/// <summary>Intercept column 'Get Field Suffix' to replace double/float with decimal where required.</summary>
private String GetColumnGetFieldSuffix(DbDfnColumn columnDfn)
{
return GetColumnGetFieldSuffix(columnDfn, config.TableClass.TreatDoubleFormatAsDecimal);
}
/// <summary>Intercept column 'Get Field Suffix' to replace double/float with decimal where required.</summary>
private static String GetColumnGetFieldSuffix(DbDfnColumn columnDfn, bool treatDoubleFormatAsDecimal)
{
String suffix = columnDfn.GetGetFieldSuffix();
if (treatDoubleFormatAsDecimal)
{
switch (columnDfn.DataType)
{
case DbColumnDataType.Single:
case DbColumnDataType.Double:
suffix = "Decimal";
break;
}
}
return suffix;
}
//-------------------------------------------------------------------
private static List<string> nullableDataTypes = new List<string>() { "Boolean", "Byte", "Int16", "Int32", "Int64", "Single", "Double", "Decimal", "DateTime" };
/// <summary>
/// Determine whether column should be treated as nullable.
/// <para>- This behaviour is restricted to selected data types.</para>
/// </summary>
private bool TreatColumnAsNullable(DbDfnColumn columnDfn)
{
return (nullableDataTypes.ContainsCI(columnDfn.GetVariableTypeName()) && columnDfn.IsNullable);
}
//-------------------------------------------------------------------
// D a t a b a s e D e f i n i t i o n C l a s s
//-------------------------------------------------------------------
private void GenerateDatabaseDefinitionClass(IEnumerable<DbDfnTable> tableDfns)
{
// Remove excluded tables.
tableDfns = tableDfns.Where(item => IsValidTable(item.Name, DefinitionOutput.DatabaseDefinitionClass)).ToList();
String filePath = config.OutputDirectory + Path.DirectorySeparatorChar + config.DefinitionClass.Classname + ".cs";
using (StreamWriter file = new StreamWriter(filePath))
{
// Database definition file:
foreach (String namespace_Base in config.DefinitionClass.Usings.OrderBy(s => s))
file.WriteLine("using " + namespace_Base + ";");
file.WriteLine("using System;");
file.WriteLine("using System.Collections.Generic;");
file.WriteLine("using System.Linq;");
file.WriteLine("");
file.WriteLine("//---------------------------------------------------------------------------");
file.WriteLine("// Code generated by Sarand Database Utilities " + DateTime.Now.Format("ddd d-MMM-yyyy HH:mm:ss"));
file.WriteLine("//---------------------------------------------------------------------------");
file.WriteLine("namespace " + config.DefinitionClass.Namespace);
file.WriteLine("{");
file.WriteLine(tab1 + "public class " + config.DefinitionClass.Classname);
file.WriteLine(tab1 + "{");
file.WriteLine(tab2 + "//-------------------------------------------------------------------");
GenerateDatabaseDefinitionTablesEnum(tableDfns, file);
GenerateDatabaseDefinitionColumnsEnum(tableDfns, file);
GenerateDatabaseDefinitionClass(tableDfns, config.DefinitionClass.Classname, file);
file.WriteLine(tab1 + "}");
file.WriteLine("}");
//file.Close(); - Unecessary as the object will be disposed at the end of the 'using' block which is the same as Close.
}
}
//-------------------------------------------------------------------
// D a t a b a s e E n u m s
//-------------------------------------------------------------------
public static void GenerateDatabaseDefinitionTablesEnum(IEnumerable<DbDfnTable> tableDfns, StreamWriter file)
{
file.WriteLine(tab2 + "// Table identifiers.");
file.WriteLine(tab2 + "public enum TableIdx");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "Unknown = 0,");
foreach (DbDfnTable tableDfn in tableDfns)
{
file.WriteLine(tab3 + tableDfn.Name + ",");
}
file.WriteLine(tab2 + "}");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
}
//-------------------------------------------------------------------
public static void GenerateDatabaseDefinitionColumnsEnum(IEnumerable<DbDfnTable> tableDfns, StreamWriter file)
{
file.WriteLine(tab2 + "// Column identifiers.");
file.WriteLine(tab2 + "public enum ColumnIdx");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "Unknown = 0,");
foreach (DbDfnTable tableDfn in tableDfns)
{
foreach (var columnDfn in tableDfn.Columns)
file.WriteLine(tab3 + tableDfn.Name + "_" + columnDfn.Name + ",");
}
file.WriteLine(tab2 + "}");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
}
//-------------------------------------------------------------------
public static void GenerateDatabaseDefinitionClass(IEnumerable<DbDfnTable> tableDfns, String classnameDefinition, StreamWriter file)
{
file.WriteLine(tab2 + "// Data members.");
file.WriteLine(tab2 + "private static readonly int tableCount = " + tableDfns.Count() + ";");
file.WriteLine(tab2 + "private static readonly int columnCount = " + tableDfns.GetColumnCount() + ";");
file.WriteLine(tab2 + "public static ulong MaxTextLen { get; private set; }");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
// Table methods.
file.WriteLine(tab2 + "// Retrieve Table details (eg. name: 'Company').");
file.WriteLine(tab2 + "public static int GetTableCount ()");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "return tableCount;");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static String GetSchemaName (TableIdx table, bool delimitReservedWords = true)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "int tableIdx = (int)table - 1;");
file.WriteLine(tab3 + "if (tableIdx < 0 || tableIdx >= tableCount) return String.Empty;");
file.WriteLine(tab3 + "String schemaName = tables[(int)tableIdx].Schema;");
file.WriteLine(tab3 + "if (delimitReservedWords) { schemaName = DelimitReservedWord(schemaName); }");
file.WriteLine(tab3 + "return schemaName;");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static String GetTableName (TableIdx table, bool delimitReservedWords = true)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "int tableIdx = (int)table - 1;");
file.WriteLine(tab3 + "if (tableIdx < 0 || tableIdx >= tableCount) return String.Empty;");
file.WriteLine(tab3 + "String tableName = tables[(int)tableIdx].Name;");
file.WriteLine(tab3 + "if (delimitReservedWords) tableName = DelimitReservedWord(tableName);");
file.WriteLine(tab3 + "return tableName;");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static String GetTableNameQual (TableIdx table, bool delimitReservedWords = true)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "int tableIdx = (int)table - 1;");
file.WriteLine(tab3 + "if (tableIdx < 0 || tableIdx >= tableCount) return String.Empty;");
file.WriteLine(tab3 + "String schemaName = tables[(int)tableIdx].Schema;");
file.WriteLine(tab3 + "String tableName = tables[(int)tableIdx].Name;");
file.WriteLine(tab3 + "if (delimitReservedWords) { schemaName = DelimitReservedWord(schemaName); tableName = DelimitReservedWord(tableName); }");
file.WriteLine(tab3 + "return (StringUtil.IsBlank(schemaName) ? \"\" : schemaName + \".\") + tableName;");
file.WriteLine(tab2 + "}");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
// Table for Column method.
file.WriteLine(tab2 + "// Identify the table that corresponds with the specified column.");
file.WriteLine(tab2 + "public static TableIdx GetTableForColumn (ColumnIdx column)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "int columnIdx = (int)column - 1;");
file.WriteLine(tab3 + "if (columnIdx < 0 || columnIdx >= columnCount) return TableIdx.Unknown;");
file.WriteLine(tab3 + "return columns[columnIdx].TableIdx;");
file.WriteLine(tab2 + "}");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
// Column methods.
file.WriteLine(tab2 + "// Retrieve the specified Column's name (Qualified include table name: '(<Table>.Column>)').");
file.WriteLine(tab2 + "public static String GetColumnName (ColumnIdx column, bool delimitReservedWords = true)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "int columnIdx = (int)column - 1;");
file.WriteLine(tab3 + "if (columnIdx < 0 || columnIdx >= columnCount) return String.Empty;");
file.WriteLine(tab3 + "String columnName = columns[columnIdx].Name;");
file.WriteLine(tab3 + "if (delimitReservedWords) columnName = DelimitReservedWord(columnName);");
file.WriteLine(tab3 + "return columnName;");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static String GetColumnNameQual (ColumnIdx column, String tableAlias = \"\", bool braces = false)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "String columnName = GetColumnName(column);");
file.WriteLine(tab3 + "if (!String.IsNullOrEmpty(columnName))");
file.WriteLine(tab3 + "{");
file.WriteLine(tab4 + "String tableName = StringUtil.EmptyOnNull(tableAlias);");
file.WriteLine(tab4 + "if (tableName.IsEmpty()) tableName = GetTableName(GetTableForColumn(column));");
file.WriteLine(tab4 + "columnName = tableName + (tableName.Length > 0 ? \".\" : \"\") + columnName;");
file.WriteLine(tab4 + "if (braces)");
file.WriteLine(tab5 + "columnName = \"(\" + columnName + \")\";");
file.WriteLine(tab3 + "}");
file.WriteLine(tab3 + "return columnName;");
file.WriteLine(tab2 + "}");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
// Reserved word methods.
file.WriteLine(tab2 + "// Reserved words.");
file.WriteLine(tab2 + "private static DbReservedWordDelim reservedWordDelim = DbReservedWordDelim.SquareBrackets;");
file.WriteLine(tab2 + "public static void SetReservedWordDelim (DbReservedWordDelim reservedWordDelim)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + classnameDefinition + ".reservedWordDelim = reservedWordDelim;");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static bool IsReservedWord (String word)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "if (String.IsNullOrEmpty(word)) return false;");
file.WriteLine(tab3 + "if (reservedWords.Contains(word, StringComparer.OrdinalIgnoreCase)) return true;");
file.WriteLine(tab3 + "return false;");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static String DelimitReservedWord (String word)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "return IsReservedWord(word) ? DelimitWord(word) : word;");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static String DelimitWord (String word)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "return DelimitWord(word, reservedWordDelim);");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static String DelimitWord (String word, DbReservedWordDelim wordDelim)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "switch (wordDelim)");
file.WriteLine(tab3 + "{");
file.WriteLine(tab4 + "case DbReservedWordDelim.None:");
file.WriteLine(tab5 + "break;");
file.WriteLine(tab4 + "case DbReservedWordDelim.DoubleQuotes:");
file.WriteLine(tab5 + "word = \"\\\"\" + word + \"\\\"\"; ");
file.WriteLine(tab5 + "break;");
file.WriteLine(tab4 + "case DbReservedWordDelim.SquareBrackets:");
file.WriteLine(tab4 + "default:");
file.WriteLine(tab5 + "word = \"[\" + word + \"]\"; ");
file.WriteLine(tab5 + "break;");
file.WriteLine(tab3 + "}");
file.WriteLine(tab3 + "return word;");
file.WriteLine(tab2 + "}");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
// Column information methods.
file.WriteLine(tab2 + "// Retrieve information about the specified Column.");
file.WriteLine(tab2 + "public static DbColumnDataType GetColDataType (ColumnIdx column)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "int columnIdx = (int)column - 1;");
file.WriteLine(tab3 + "if (columnIdx < 0 || columnIdx >= columnCount) return DbColumnDataType.Unknown;");
file.WriteLine(tab3 + "return columns[columnIdx].DataType;");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static short GetColNativeDataType (ColumnIdx column)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "int columnIdx = (int)column - 1;");
file.WriteLine(tab3 + "if (columnIdx < 0 || columnIdx >= columnCount) return 0;");
file.WriteLine(tab3 + "return columns[columnIdx].NativeDataType;");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static void SetMaxTextLen (ulong maxTextLen)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + classnameDefinition + ".MaxTextLen = maxTextLen;");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static bool IsColFmtText (ColumnIdx column)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "int columnIdx = (int)column - 1;");
file.WriteLine(tab3 + "if (columnIdx < 0 || columnIdx >= columnCount) return false;");
file.WriteLine(tab3 + "return (columns[columnIdx].DataType == DbColumnDataType.VarChar);");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static ulong GetColTextLen (ColumnIdx column)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "int columnIdx = (int)column - 1;");
file.WriteLine(tab3 + "if (columnIdx < 0 || columnIdx >= columnCount) return 0;");
file.WriteLine(tab3 + "if (columns[columnIdx].DataType == DbColumnDataType.VarChar)");
file.WriteLine(tab3 + "{");
file.WriteLine(tab4 + "ulong textLen = columns[columnIdx].DataLen;");
file.WriteLine(tab4 + "if (MaxTextLen > 0 && textLen > MaxTextLen) textLen = MaxTextLen;");
file.WriteLine(tab4 + "return textLen;");
file.WriteLine(tab3 + "}");
file.WriteLine(tab3 + "return 0;");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static bool IsColFmtBool (ColumnIdx column)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "int columnIdx = (int)column - 1;");
file.WriteLine(tab3 + "if (columnIdx < 0 || columnIdx >= columnCount) return false;");
file.WriteLine(tab3 + "return (columns[columnIdx].DataType == DbColumnDataType.Bit);");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static bool IsColFmtNumeric (ColumnIdx column)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "int columnIdx = (int)column - 1;");
file.WriteLine(tab3 + "if (columnIdx < 0 || columnIdx >= columnCount) return false;");
file.WriteLine(tab3 + "switch (columns[columnIdx].DataType)");
file.WriteLine(tab3 + "{");
file.WriteLine(tab4 + "case DbColumnDataType.TinyInt:");
file.WriteLine(tab4 + "case DbColumnDataType.SmallInt:");
file.WriteLine(tab4 + "case DbColumnDataType.Int:");
file.WriteLine(tab4 + "case DbColumnDataType.BigInt:");
file.WriteLine(tab4 + "case DbColumnDataType.Single:");
file.WriteLine(tab4 + "case DbColumnDataType.Double:");
file.WriteLine(tab4 + "case DbColumnDataType.Decimal:");
file.WriteLine(tab5 + "return true;");
file.WriteLine(tab3 + "}");
file.WriteLine(tab3 + "return false;");
file.WriteLine(tab2 + "}");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
// Table names.
file.WriteLine(tab2 + "// Table definitions.");
file.WriteLine(tab2 + "private class TableDfn");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "internal String Schema { get; set; }");
file.WriteLine(tab3 + "internal String Name { get; set; }");
file.WriteLine(tab3 + "internal TableDfn (String schema, String name)");
file.WriteLine(tab3 + "{");
file.WriteLine(tab4 + "this.Schema= schema;");
file.WriteLine(tab4 + "this.Name = name;");
file.WriteLine(tab3 + "}");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "private static readonly TableDfn[] tables =");
file.WriteLine(tab2 + "{");
foreach (DbDfnTable tableDfn in tableDfns)
file.WriteLine(tab3 + "new TableDfn(\"" + tableDfn.Schema + "\",\"" + tableDfn.Name + "\"),");
file.WriteLine(tab2 + "};");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
// Table Column definitions.
file.WriteLine(tab2 + "// Table column definitions.");
file.WriteLine(tab2 + "private class ColumnDfn");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "internal TableIdx TableIdx { get; set; }");
file.WriteLine(tab3 + "internal String Name { get; set; }");
file.WriteLine(tab3 + "internal DbColumnDataType DataType { get; set; }");
file.WriteLine(tab3 + "internal short NativeDataType { get; set; }");
file.WriteLine(tab3 + "internal bool IsIdentity { get; set; }");
file.WriteLine(tab3 + "internal ulong DataLen { get; set; }");
file.WriteLine(tab3 + "internal ColumnDfn (int tableIdx, String name, int dataType, short nativeDataType, bool isIdentity, ulong dataLen)");
file.WriteLine(tab3 + "{");
file.WriteLine(tab4 + "this.TableIdx = (TableIdx)tableIdx;");
file.WriteLine(tab4 + "this.Name = name;");
file.WriteLine(tab4 + "this.DataType = (DbColumnDataType)dataType;");
file.WriteLine(tab4 + "this.NativeDataType = nativeDataType;");
file.WriteLine(tab4 + "this.IsIdentity = isIdentity;");
file.WriteLine(tab4 + "this.DataLen = dataLen;");
file.WriteLine(tab3 + "}");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "private static readonly ColumnDfn[] columns =");
file.WriteLine(tab2 + "{");
uint tableIdx = 0;
foreach (DbDfnTable tableDfn in tableDfns)
{
tableIdx++;
foreach (var columnDfn in tableDfn.Columns)
file.WriteLine(tab3 + "new ColumnDfn(" + tableIdx.ToString() + ",\"" + columnDfn.Name + "\"," + ((int)columnDfn.DataType).ToString() + "," + columnDfn.DataTypeNative.ToString() + "," + (columnDfn.IsIdentity ? "true" : "false") + "," + columnDfn.Size.ToString() + "),");
}
file.WriteLine(tab2 + "};");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
// Reserved words.
file.WriteLine(tab2 + "// Reserved words.");
file.WriteLine(tab2 + "private static readonly HashSet<String> reservedWords = new HashSet<String>()");
file.WriteLine(tab2 + "{");
foreach (String reservedword in reservedWords)
file.WriteLine(tab3 + "\"" + reservedword + "\", ");
file.WriteLine(tab2 + "};");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
}
//-------------------------------------------------------------------
// T a b l e C l a s s
//-------------------------------------------------------------------
private void GenerateTableInterfaceClass(DbDfnTable tableDfn)
{
String className = tableDfn.Name + "_Db";
if (!StringUtil.IsEmpty(tableDfn.Schema) && !tableDfn.Schema.EqualsCI("dbo"))
{
className = config.Schema.SchemaNameCapitalisation.GetValueOrDefault(tableDfn.Schema, StringUtil.CapitaliseFirst(tableDfn.Schema)) + "_" + className;
}
List<String> primaryColumnNames = tableDfn.GetPrimaryColumnNames();
String identityColumnName = tableDfn.Columns.GetIdentityColumnName();
String identityColumnVariableTypeName = tableDfn.Columns.GetIdentityColumnVariableTypeName();
String identityColumnCastFromInt64 = (!identityColumnVariableTypeName.EqualsCI("Int64") && !identityColumnVariableTypeName.EqualsCI("long") ? "(" + identityColumnVariableTypeName + ")" : "");
// Class 'using's.
List<String> usingNamespaces = new List<string>(config.TableClass.Usings);
usingNamespaces.AddRange(new List<String>()
{
config.TableClass.Namespace_BaseClass,
"System",
"System.Collections.Generic",
"System.Data.Common",
config.DotNetVersion == DotNetVersion.Framework? "System.Data.Odbc" : "",
config.DotNetVersion == DotNetVersion.Core3 ? "Microsoft.Data.SqlClient" : "System.Data.SqlClient",
"System.Linq"
});
usingNamespaces.RemoveBlanks();
usingNamespaces.RemoveDuplicatesCI();
usingNamespaces.Sort();
// Alternative table names.
List<String> alternativeTableNames = new List<string>();
if (config.Schema.AlternativeTableNames.ContainsKey(tableDfn.Name))
alternativeTableNames.AddRange(config.Schema.AlternativeTableNames[tableDfn.Name]);
// List of columns to be ignored on update.
List<String> columnsIgnoredOnUpdate = new List<string>();
foreach (StringPair insertOnlyColumns in config.Schema.InsertOnlyColumns.FindAll(x => Regex.IsMatch(tableDfn.Name, x.Item1, RegexOptions.IgnoreCase)))
columnsIgnoredOnUpdate.AddRange(insertOnlyColumns.Item2.Split(','));
for (int i = 0; i < columnsIgnoredOnUpdate.Count; i++)
columnsIgnoredOnUpdate[i] = columnsIgnoredOnUpdate[i].Trim(' ');
String filePath = config.OutputDirectory + Path.DirectorySeparatorChar + className + ".cs";
using (StreamWriter file = new StreamWriter(filePath))
{
// Database definition file.
foreach (String usingNamespace in usingNamespaces)
file.WriteLine("using " + usingNamespace + ";");
file.WriteLine("");
file.WriteLine("//---------------------------------------------------------------------------");
file.WriteLine("// Code generated by Sarand Database Utilities " + DateTime.Now.Format("ddd d-MMM-yyyy HH:mm:ss"));
file.WriteLine("//---------------------------------------------------------------------------");
file.WriteLine("namespace " + config.TableClass.Namespace);
file.WriteLine("{");
file.WriteLine(tab1 + "internal class " + className + " : " + config.TableClass.BaseClass);
file.WriteLine(tab1 + "{");
file.WriteLine(tab2 + "//-------------------------------------------------------------------");
file.WriteLine(tab2 + "// Column definitions.");
file.WriteLine(tab2 + "public class ColumnsData");
file.WriteLine(tab2 + "{");
foreach (var columnDfn in tableDfn.Columns)
{
String columnDataClassName = "ColumnData" + GetColumnVariableTypeName(columnDfn) + (TreatColumnAsNullable(columnDfn) ? "Nullable" : "");
file.WriteLine(tab3 + "public " + columnDataClassName + " _" + columnDfn.Name + " { get; } = new " + columnDataClassName + "(\"" + columnDfn.Name + "\"" + (columnDfn.IsIdentity ? ", true" : "") + ");");
}
file.WriteLine(tab2 + "}");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
file.WriteLine(tab2 + "// Data members.");
file.WriteLine(tab2 + "protected static List<String> fields { get; } = new List<String>()");
file.WriteLine(tab2 + "{");
foreach (var columnDfn in tableDfn.Columns) file.WriteLine(tab3 + "\"" + columnDfn.Name + "\",");
file.WriteLine(tab2 + "};");
file.WriteLine(tab2 + "protected static List<String> fieldsId { get; } = new List<String>()");
file.WriteLine(tab2 + "{");
foreach (var columnDfn in tableDfn.Columns.FindAll(item => item.IsIdentity)) file.WriteLine(tab3 + "\"" + columnDfn.Name + "\",");
file.WriteLine(tab2 + "};");
file.WriteLine(tab2 + "protected static List<String> fieldsPrimary { get; } = new List<String>()");
file.WriteLine(tab2 + "{");
foreach (String columnName in primaryColumnNames) file.WriteLine(tab3 + "\"" + columnName + "\",");
file.WriteLine(tab2 + "};");
file.WriteLine(tab2 + "protected static List<String> fieldsNullable { get; } = new List<String>()");
file.WriteLine(tab2 + "{");
foreach (var columnDfn in tableDfn.Columns.FindAll(item => item.IsNullable)) file.WriteLine(tab3 + "\"" + columnDfn.Name + "\",");
file.WriteLine(tab2 + "};");
file.WriteLine(tab2 + "protected static List<String> fieldsIgnoreOnUpdate { get; } = new List<String>()");
file.WriteLine(tab2 + "{");
foreach (String columnName in columnsIgnoredOnUpdate) file.WriteLine(tab3 + "\"" + columnName + "\",");
file.WriteLine(tab2 + "};");
/*
file.WriteLine(tab2 + "protected static List<String> fieldsNonId { get; } = new List<String>()");
file.WriteLine(tab2 + "{");
foreach (var columnDfn in tableDfn.Columns.FindAll(item => !item.IsIdentity)) file.WriteLine(tab3 + "\"" + columnDfn.Name + "\",");
file.WriteLine(tab2 + "};");
*/
//-----------------------------------------------------------
// Construction.
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
file.WriteLine(tab2 + "// Construction.");
file.WriteLine(tab2 + "internal " + className + " (" + config.TableClass.ClassName_DatabaseInfo + " dbInfo" + (!config.TableClass.MandatoryConstructorDbInfo ? " = null" : "") + ") : base(dbInfo)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab2 + "}");
//-----------------------------------------------------------
// Properties.
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
file.WriteLine(tab2 + "// Properties.");
file.WriteLine(tab2 + "public override String SchemaName { get; } = \"" + tableDfn.Schema + "\";");
if (alternativeTableNames.Count == 0)
file.WriteLine(tab2 + "public override String TableName { get; } = \"" + tableDfn.Name + "\";");
else
{
// Logic to handle alternative table names.
file.WriteLine(tab2 + "public override String TableName { get { return GetActualTableName(\"" + tableDfn.Name + "\"); } }");
file.WriteLine(tab2 + "public override List<String> AlternativeTableNames { get; } = new List<string>() { " + alternativeTableNames.Concat(", ", "\"", "\"") + " };");
}
file.WriteLine(tab2 + "public String TableNameFmt { get { return (!String.IsNullOrEmpty(SchemaName) ? \"[\" + SchemaName + \"].\" : \"\") + \"[\" + TableName + \"]\"; } }");
file.WriteLine(tab2 + "public static List<String> Fields { get { return new List<String>(fields); } }");
file.WriteLine(tab2 + "public static List<String> FieldsId { get { return new List<String>(fieldsId); } }");
file.WriteLine(tab2 + "public static List<String> FieldsNonId { get { return fields.FindAll(item => !fieldsId.ContainsCI(item)); } }");
file.WriteLine(tab2 + "// Columns.");
file.WriteLine(tab2 + "public ColumnsData Cols { get; } = new ColumnsData();");
foreach (var columnDfn in tableDfn.Columns)
file.WriteLine(tab2 + "public " + GetColumnVariableType(columnDfn) + (TreatColumnAsNullable(columnDfn) ? "?" : "") + " _" + columnDfn.Name + " { get { return Cols._" + columnDfn.Name + ".Value; } set { Cols._" + columnDfn.Name + ".Value = value; } }");
file.WriteLine(tab2 + "// Existing columns - confirmed on database if table exists.");
file.WriteLine(tab2 + "public List<String> ExistingColumnNames { get { return GetExistingColumnNames(Fields); } }");
file.WriteLine(tab2 + "public List<String> ExistingColumnNamesNonId { get { return GetExistingColumnNames(FieldsNonId); } }");
file.WriteLine(tab2 + "public List<String> UpdatableColumns { get { return ExistingColumnNamesNonId.Where(item => !fieldsPrimary.ContainsCI(item) && !fieldsIgnoreOnUpdate.ContainsCI(item)).ToList(); } }");
//-----------------------------------------------------------
// Population.
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
file.WriteLine(tab2 + "// Population.");
file.WriteLine(tab2 + "public override void PopulateFrom (DbCommand dbCommand, String tableAlias, String filter)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "dbCommand.CommandText =");
file.WriteLine(tab4 + "\"SELECT \" + ExistingColumnNames.Concat(\", \", (!String.IsNullOrEmpty(tableAlias) ? tableAlias + \".\" : \"\") + \"[\", \"]\") + \" \" +");
file.WriteLine(tab4 + "\"FROM \" + TableNameFmt + (!String.IsNullOrEmpty(tableAlias) ? \" \" + tableAlias : \"\") + \" \" + ");
file.WriteLine(tab4 + "(!String.IsNullOrEmpty(filter) ? \"WHERE \" + filter : \"\");");
file.WriteLine(tab3 + "Log(GetType().Name + \".PopulateFrom\", dbCommand.CommandText);");
file.WriteLine(tab3 + "using (DbDataReader dbDataReader = dbCommand.ExecuteReader())");
file.WriteLine(tab3 + "{");
file.WriteLine(tab4 + "dbDataReader.Read();");
file.WriteLine(tab4 + "PopulateFrom(dbDataReader);");
file.WriteLine(tab3 + "}");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public override void PopulateFrom (DbDataReader dbDataReader)");
file.WriteLine(tab2 + "{");
foreach (var columnDfn in tableDfn.Columns)
file.WriteLine(tab3 + "_" + columnDfn.Name + " = GetField" + GetColumnGetFieldSuffix(columnDfn) + (TreatColumnAsNullable(columnDfn) ? "Nullable" : "") + "(dbDataReader, \"" + columnDfn.Name + "\", _" + columnDfn.Name + ");");
file.WriteLine(tab2 + "}");
//-----------------------------------------------------------
// Prepare Insert command.
// SQL:
// Parameters can be named.
// Multiple queries allowed - can append 'SELECT Scope_Identity();' to insert query.
// ODBC:
// Parameters identified as '?' and matched by position in parameter list.
// Single queries only. Use Max(Id) to retrieve identity value.
//-----------------------------------------------------------
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
file.WriteLine(tab2 + "// Insert command.");
file.WriteLine(tab2 + "public override bool ExecuteInsertCommand (DbCommand dbCommand)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "List<String> columnNames = ExistingColumnNamesNonId;");
if (!String.IsNullOrEmpty(identityColumnName))
{
file.WriteLine(tab3 + "// Avoid insert if Identity field is already valid.");
file.WriteLine(tab3 + "if (_" + identityColumnName + " != 0) throw new Exception(\"Invalid for Insert - item already has a valid Id\"); ");
}
file.WriteLine(tab3 + "// Construct query.");
file.WriteLine(tab3 + "String query =");
file.WriteLine(tab4 + "\"INSERT INTO \" + TableNameFmt + \" \" +");
file.WriteLine(tab4 + "\"(\"+columnNames.Concat(\",\",\"[\",\"]\")+\") \";");
if (!String.IsNullOrEmpty(identityColumnName))
file.WriteLine(tab3 + "query += \"Output Inserted." + identityColumnName + " \";");
List<String> columnsValuesToInsertSql = new List<String>();
foreach (var columnDfn in tableDfn.Columns.Where(col => !col.IsIdentity))
columnsValuesToInsertSql.Add("@" + columnDfn.Name);
file.WriteLine(tab3 + "if (dbCommand is SqlCommand)");
file.WriteLine(tab4 + "query += \"VALUES (\" + columnNames.Concat(\",\", \"@\", \"\") + \") \";");
file.WriteLine(tab3 + "else query += \"VALUES (\" + " + (config.SarandCommonVersion == SarandCommonVersion.VS2019 ? "StringListUtil" : "StringList") + ".CreateList(\"?\", columnNames.Count).Concat(\",\") + \") \";");
if (!String.IsNullOrEmpty(identityColumnName) && config.DbmsOutput == Dbms.SQL)
file.WriteLine(tab3 + "query += SELECT Scope_Identity();"); // NB @@Identity for Access.
file.WriteLine(tab3 + "dbCommand.CommandText = query;");
file.WriteLine(tab3 + "Log(GetType().Name + \".ExecuteInsertCommand\", dbCommand.CommandText);");
file.WriteLine(tab3 + "// Populate parameters.");
file.WriteLine(tab3 + "dbCommand.Parameters.Clear();");
foreach (var columnDfn in tableDfn.Columns.Where(col => !col.IsIdentity))
file.WriteLine(tab3 + "if (columnNames.ContainsCI(\"" + columnDfn.Name + "\")) AddCommandParameter(dbCommand, \"@" + columnDfn.Name + "\", _" + columnDfn.Name + ");");
file.WriteLine(tab3 + "// Execute insert command.");
file.WriteLine(tab3 + "bool commandSuccess = false;");
if (config.DbmsOutput == Dbms.SQL)
{
if (!String.IsNullOrEmpty(identityColumnName))
{
// Execute single command to insert and query 'Scope_Identity' to retrieve Identity value.
file.WriteLine(tab3 + "_" + identityColumnName + " = " + identityColumnCastFromInt64 + "Convert.ToInt64(dbCommand.ExecuteScalar());");
file.WriteLine(tab3 + "commandSuccess = (_" + identityColumnName + " > 0);");
}
else
{
// Execute query and retrieve number of records (may return -1).
file.WriteLine(tab3 + "int executeNonQuery = dbCommand.ExecuteNonQuery();");
file.WriteLine(tab3 + "commandSuccess = true;");
}
}
else
{
// Execute query.
file.WriteLine(tab3 + "int executeNonQuery = dbCommand.ExecuteNonQuery();");
file.WriteLine(tab3 + "if (executeNonQuery == 1)"); // No of records inserted? Returns -1?
file.WriteLine(tab3 + "{");
if (!String.IsNullOrEmpty(identityColumnName))
{
// Retrieve Identity value.
file.WriteLine(tab4 + "dbCommand.CommandText = \"SELECT Max(" + identityColumnName + ") FROM \" + TableNameFmt + \";\";");
file.WriteLine(tab4 + "_" + identityColumnName + " = " + identityColumnCastFromInt64 + "Convert.ToInt64(dbCommand.ExecuteScalar());");
file.WriteLine(tab4 + "commandSuccess = (_" + identityColumnName + " > 0);");
}
else
{
file.WriteLine(tab4 + "commandSuccess = true;");
}
file.WriteLine(tab3 + "}");
}
file.WriteLine(tab3 + "return commandSuccess;");
file.WriteLine(tab2 + "}");
//-----------------------------------------------------------
// Prepare Update command.
// Filter: Primary index values.
// Update: Non-primary index values.
// SQL:
// Parameters can be named.
// ODBC:
// Parameters identified as '?' and matched by position in parameter list.
// Single queries only. Use Max(Id) to retrieve identity value.
//-----------------------------------------------------------
// Construct update command.
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
file.WriteLine(tab2 + "// Update command.");
file.WriteLine(tab2 + "public override bool ExecuteUpdateCommand (DbCommand dbCommand, List<String> columnsToUpdate = null)");
file.WriteLine(tab2 + "{");
if (!String.IsNullOrEmpty(identityColumnName))
{
file.WriteLine(tab3 + "// Avoid update if Identity field isn't valid.");
file.WriteLine(tab3 + "if (_" + identityColumnName + " == 0) throw new Exception(\"Invalid for Update - item has an invalid Id\"); ");
}
file.WriteLine(tab3 + "// Columns to update.");
file.WriteLine(tab3 + "List<String> columnNames = (columnsToUpdate?.Any() ?? false ? columnsToUpdate : UpdatableColumns).Where(col => UpdatableColumns.ContainsCI(col)).ToList();");
file.WriteLine(tab3 + "if (!columnNames.Any())");
file.WriteLine(tab3 + "{");
file.WriteLine(tab4 + "SaLogger.Warn($\"{SysUtil.Fn} No columns to update. [{GetType().Name}]\");");
file.WriteLine(tab4 + "return false;");
file.WriteLine(tab3 + "}");
file.WriteLine(tab3 + "// Construct query.");
file.WriteLine(tab3 + "String query = \"UPDATE \" + TableNameFmt + \" SET \";");
List<String> columnsValuesToUpdate = new List<String>();
List<String> columnsValuesToUpdateSql = new List<String>();
foreach (var columnDfn in tableDfn.Columns)
{
if (primaryColumnNames.Any(col => col.EqualsCI(columnDfn.Name))) continue;
if (columnsIgnoredOnUpdate.Any(col => col.EqualsCI(columnDfn.Name))) continue;
// Delimit reserved column names.
String columnNameSql = columnDfn.Name;
if (reservedWords.ToList().ContainsCI(columnNameSql))
columnNameSql = "[" + columnNameSql + "]";
columnsValuesToUpdate.Add(columnDfn.Name + "=?");
columnsValuesToUpdateSql.Add(columnNameSql + "=@" + columnDfn.Name);
}
//-----------------------------------------------------------
// SQL Update.
file.WriteLine(tab3 + "if (dbCommand is SqlCommand)");
file.WriteLine(tab3 + "{");
file.WriteLine(tab4 + "query += StringPairList.CreateFrom(columnNames.Bracket(\"[\",\"]\"),columnNames).Concat(\"=@\").Concat(\", \") + \" \";");
List<String> whereFilterSql = new List<string>();
foreach (var primaryColumnName in primaryColumnNames)
whereFilterSql.Add(primaryColumnName + "=@" + primaryColumnName);
file.WriteLine(tab4 + "query += \"WHERE " + whereFilterSql.Concat(" AND ") + ";\";");
file.WriteLine(tab3 + "}");
//-----------------------------------------------------------
// Non-SQL Update.
file.WriteLine(tab3 + "else");
file.WriteLine(tab3 + "{");
file.WriteLine(tab4 + "query += columnNames.Concat(\", \", \"\", \"=?\") + \" \";");
List<String> whereFilterNonSql = new List<string>();
foreach (var primaryColumnName in primaryColumnNames)
whereFilterNonSql.Add(primaryColumnName + "=?");
file.WriteLine(tab4 + "query += \"WHERE " + whereFilterNonSql.Concat(" AND ") + ";\";");
file.WriteLine(tab3 + "}");
//-----------------------------------------------------------
// Populate parameters and execute update command.
file.WriteLine(tab3 + "dbCommand.CommandText = query;");
file.WriteLine(tab3 + "Log(GetType().Name + \".ExecuteUpdateCommand\", dbCommand.CommandText);");
file.WriteLine(tab3 + "// Populate parameters.");
file.WriteLine(tab3 + "dbCommand.Parameters.Clear();");
foreach (var columnDfn in tableDfn.Columns.FindAll(item => !primaryColumnNames.Contains(item.Name) && !columnsIgnoredOnUpdate.Contains(item.Name)))
file.WriteLine(tab3 + "if (columnNames.ContainsCI(\"" + columnDfn.Name + "\")) AddCommandParameter(dbCommand, \"@" + columnDfn.Name + "\", _" + columnDfn.Name + ");");
foreach (var primaryColumnName in primaryColumnNames)
file.WriteLine(tab3 + "AddCommandParameter(dbCommand, \"@" + primaryColumnName + "\", _" + primaryColumnName + ");");
file.WriteLine(tab3 + "int executeNonQueryResult = dbCommand.ExecuteNonQuery();");
file.WriteLine(tab3 + "return (executeNonQueryResult == 1);");
file.WriteLine(tab2 + "}");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
// Close class.
file.WriteLine(tab1 + "}");
file.WriteLine("}");
//file.Close(); - Unecessary as the object will be disposed at the end of the 'using' block.
}
}
//-------------------------------------------------------------------
}
//=======================================================================
}