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

674 lines
26 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Common;
using System.Linq;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Dbas.Base;
using Microsoft.Data.SqlClient;
using Sarand.Net.Standard.Base.Utils;
using Sarand.Net.Standard.Base.App;
namespace Sarand.Net.Standard.Dbas.Data
{
//=======================================================================
public abstract class DbDataItem : IDbDataItem
{
//-------------------------------------------------------------------
// D a t a b a s e I n f o
//-------------------------------------------------------------------
// Definitions.
/// <summary>
/// Database information - object supplied by main application.
/// <para>NB Application may have multiple databases with schema differences.</para>
/// <para>Each instance of a DbDataItem must be database specific.</para>
/// </summary>
public class DatabaseInfo : IDatabaseInfo
{
// Data members.
private readonly List<DbDfnTable> tables;
private static readonly String defaultSchemaName = "dbo";
// Construction.
public DatabaseInfo(ISacsDatabase db)
{
this.DatabaseName = db.DatabaseName;
this.tables = db.GetTableDfns();
}
// Properties.
public String DatabaseName { get; }
public String Context { get { return StringUtil.OnEmpty(DatabaseName, "UnknownDb"); } }
// Database schema.
public DbDfnTable GetTableDefinition(String schemaName, String tableName)
{
foreach (DbDfnTable table in tables.FindAll(item => item.Name.EqualsCI(tableName)))
{
if (StringUtil.OnEmpty(table.Schema, defaultSchemaName).EqualsCI(StringUtil.OnEmpty(schemaName, defaultSchemaName)))
return table;
}
return null;
}
public bool TableExists(String schemaName, String tableName)
{
return GetTableDefinition(schemaName, tableName) != null;
}
public bool ColumnExists(String schemaName, String tableName, String columnName)
{
DbDfnTable table = GetTableDefinition(schemaName, tableName);
if (table == null) return false;
return table.HasColumnByName(columnName);
}
public List<DbDfnColumn> GetColumnsForTable(String schemaName, String tableName)
{
DbDfnTable table = GetTableDefinition(schemaName, tableName);
if (table != null) return table.Columns;
return new List<DbDfnColumn>();
}
}
//-------------------------------------------------------------------
// C o l u m n D a t a
//-------------------------------------------------------------------
/// <summary>Column data - column definition for DbDataItem.</summary>
public class ColumnData
{
protected ColumnData(String name, bool identity = false)
{
Name = name;
Identity = identity;
}
public String Name { get; }
public bool Identity { get; }
}
public class ColumnDataString : ColumnData
{
public ColumnDataString(String name, bool identity = false) : base(name, identity) { }
public String Value { get; set; } = String.Empty;
}
public class ColumnDataBoolean : ColumnData
{
public ColumnDataBoolean(String name, bool identity = false) : base(name, identity) { }
public Boolean Value { get; set; } = false;
}
public class ColumnDataBooleanNullable : ColumnData
{
public ColumnDataBooleanNullable(String name, bool identity = false) : base(name, identity) { }
public Boolean? Value { get; set; } = null;
}
public class ColumnDataByte : ColumnData
{
public ColumnDataByte(String name, bool identity = false) : base(name, identity) { }
public Byte Value { get; set; } = 0;
}
public class ColumnDataByteNullable : ColumnData
{
public ColumnDataByteNullable(String name, bool identity = false) : base(name, identity) { }
public Byte? Value { get; set; } = null;
}
public class ColumnDataInt16 : ColumnData
{
public ColumnDataInt16(String name, bool identity = false) : base(name, identity) { }
public Int16 Value { get; set; } = 0;
}
public class ColumnDataInt16Nullable : ColumnData
{
public ColumnDataInt16Nullable(String name, bool identity = false) : base(name, identity) { }
public Int16? Value { get; set; } = null;
}
public class ColumnDataInt32 : ColumnData
{
public ColumnDataInt32(String name, bool identity = false) : base(name, identity) { }
public Int32 Value { get; set; } = 0;
}
public class ColumnDataInt32Nullable : ColumnData
{
public ColumnDataInt32Nullable(String name, bool identity = false) : base(name, identity) { }
public Int32? Value { get; set; } = null;
}
public class ColumnDataInt64 : ColumnData
{
public ColumnDataInt64(String name, bool identity = false) : base(name, identity) { }
public Int64 Value { get; set; } = 0;
}
public class ColumnDataInt64Nullable : ColumnData
{
public ColumnDataInt64Nullable(String name, bool identity = false) : base(name, identity) { }
public Int64? Value { get; set; } = null;
}
public class ColumnDataSingle : ColumnData
{
public ColumnDataSingle(String name, bool identity = false) : base(name, identity) { }
public Single Value { get; set; } = 0;
}
public class ColumnDataSingleNullable : ColumnData
{
public ColumnDataSingleNullable(String name, bool identity = false) : base(name, identity) { }
public Single? Value { get; set; } = null;
}
public class ColumnDataDouble : ColumnData
{
public ColumnDataDouble(String name, bool identity = false) : base(name, identity) { }
public Double Value { get; set; } = 0;
}
public class ColumnDataDecimal : ColumnData
{
public ColumnDataDecimal(String name, bool identity = false) : base(name, identity) { }
public Decimal Value { get; set; } = 0;
}
public class ColumnDataDecimalNullable : ColumnData
{
public ColumnDataDecimalNullable(String name, bool identity = false) : base(name, identity) { }
public Decimal? Value { get; set; } = null;
}
public class ColumnDataDateTime : ColumnData
{
public ColumnDataDateTime(String name, bool identity = false) : base(name, identity) { }
public DateTime Value { get; set; } = DateTime.MinValue;
}
public class ColumnDataDateTimeNullable : ColumnData
{
public ColumnDataDateTimeNullable(String name, bool identity = false) : base(name, identity) { }
public DateTime? Value { get; set; } = null;
}
public class ColumnDataGuid : ColumnData
{
public ColumnDataGuid(String name, bool identity = false) : base(name, identity) { }
public Guid Value { get; set; } = default(Guid);
}
public class ColumnDataGuidNullable : ColumnData
{
public ColumnDataGuidNullable(String name, bool identity = false) : base(name, identity) { }
public Guid Value { get; set; } = default(Guid);
}
public class ColumnDataByteArray : ColumnData
{
public ColumnDataByteArray(String name, bool identity = false) : base(name, identity) { }
public Byte[] Value { get; set; } = null;
}
public class ColumnDataByteArrayNullable : ColumnData
{
public ColumnDataByteArrayNullable(String name, bool identity = false) : base(name, identity) { }
public Byte[] Value { get; set; } = null;
}
//-------------------------------------------------------------------
// D b D a t a I t e m
//-------------------------------------------------------------------
// Data members.
private List<String> existingColumnNamesFull = null;
//-------------------------------------------------------------------
// Construction.
protected DbDataItem(IDatabaseInfo dbInfo = null)
{
DbInfo = dbInfo;
}
//-------------------------------------------------------------------
// Properties.
protected IDatabaseInfo DbInfo { get; }
public abstract String SchemaName { get; }
public abstract String TableName { get; }
public virtual List<String> AlternativeTableNames { get; } = new List<string>();
public static List<String> MissingColumns { get { columnsMissing.Sort(); return new List<string>(columnsMissing); } }
//-------------------------------------------------------------------
/// <summary>Determine the table name used on the database which can differ if alternative names are available.</summary>
protected String GetActualTableName(String tableName)
{
if (DbInfo != null)
{
if (DbInfo.TableExists(SchemaName, tableName)) return tableName;
foreach (String tableNameAlternate in AlternativeTableNames)
if (DbInfo.TableExists(SchemaName, tableNameAlternate)) return tableNameAlternate;
}
return tableName;
}
//-------------------------------------------------------------------
// Population.
public abstract void PopulateFrom(DbCommand dbCommand, String tableAlias, String filter);
public abstract void PopulateFrom(DbDataReader dbdataReader);
//-------------------------------------------------------------------
// Database schema.
public bool ColumnExists(String columnName)
{
if (DbInfo != null)
return DbInfo.ColumnExists(SchemaName, TableName, columnName);
return true;
}
public List<String> GetExistingColumnNames(List<String> columnNames)
{
List<String> columnNamesExisting = new List<string>(columnNames);
if (existingColumnNamesFull == null)
{
// 'Existing column names (full)' contains the full list of columns confirmed to be on the database.
// NB The list will be empty if no DbInfo supplied or the table is not found on the database.
if (DbInfo != null)
{
List<DbDfnColumn> existingColumns = DbInfo.GetColumnsForTable(SchemaName, TableName);
existingColumnNamesFull = existingColumns.GetNames();
}
else existingColumnNamesFull = new List<string>();
}
if (existingColumnNamesFull.Count > 0)
{
// Remove columns that don't exist on the table.
columnNamesExisting.RemoveAll(item => !existingColumnNamesFull.ContainsCI(item));
}
return columnNamesExisting;
}
//-------------------------------------------------------------------
// Data Reader interface.
/// <summary>
/// Get column index by name.
/// <para>Returns -1 if not found and logs message.</para>
/// </summary>
protected int GetColumnOrdinal(DbDataReader dbDataReader, String columnName)
{
// Identify whether the specified column name is in the list of columns in the results set.
// NB Efficient as doesn't load the table schema and avoids logging of exception.
// Ref. https://stackoverflow.com/questions/373230/check-for-column-name-in-a-sqldatareader-object
bool columnExists = Enumerable.Range(0, dbDataReader.FieldCount).Any(i => string.Equals(dbDataReader.GetName(i), columnName, StringComparison.OrdinalIgnoreCase));
if (columnExists)
return dbDataReader.GetOrdinal(columnName);
// Invalid column name for result set.
if (DbInfo != null && !ColumnExists(columnName))
LogMissingColumn(columnName);
else SaLogger.Warn($"{SysUtil.Fn} Column not found in result set: '{columnName}'");
return -1;
/*
* Dec-2018 Previous logic trapping specific exception.
* Works well but automatically logs exception to debug console.
try
{
return dbDataReader.GetOrdinal(columnName);
}
catch (Exception exc)
{
if (exc.GetType().Name.EqualsCI("IndexOutOfRangeException"))
{
// Invalid column name for result set.
if (DbInfo != null && !ColumnExists(columnName))
{
String columnIdentifier = DbInfo.Context+"."+(!StringUtil.IsEmpty(SchemaName)?SchemaName+".":"")+TableName+"."+columnName;
if (!missingColumns.ContainsCI(columnIdentifier))
{
missingColumns.Add(columnIdentifier);
// Message is only logged on first occurence.
SaLogger.Debug($"{SysUtil.Fn} Column not found on database: {columnIdentifier}");
}
}
else SaLogger.Warn($"{SysUtil.Fn} Column not found in result set: '{columnName}'");
return -1;
}
}
return -1;
*/
}
//-------------------------------------------------------------------
// Retrieve field values.
public String GetFieldString(DbDataReader dbDataReader, String columnName, String defaultValue)
{
int columnIdx = GetColumnOrdinal(dbDataReader, columnName);
if (columnIdx < 0) return defaultValue;
// Check for null value (to avoid throwing exception).
if (!dbDataReader.IsDBNull(columnIdx))
{
Type dataType = dbDataReader.GetFieldType(columnIdx);
// Expected data type.
if (dataType == typeof(String))
return dbDataReader.GetString(columnIdx);
LogAlternativeTypeColumn(columnName, typeof(String), dataType);
}
return defaultValue;
}
public Boolean GetFieldBoolean(DbDataReader dbDataReader, String columnName, Boolean defaultValue)
{
return GetFieldBooleanNullable(dbDataReader, columnName, defaultValue) ?? defaultValue;
}
public Boolean? GetFieldBooleanNullable(DbDataReader dbDataReader, String columnName, Boolean? defaultValue)
{
int columnIdx = GetColumnOrdinal(dbDataReader, columnName);
if (columnIdx < 0) return defaultValue;
// Check for null value (to avoid throwing exception).
if (!dbDataReader.IsDBNull(columnIdx))
{
Type dataType = dbDataReader.GetFieldType(columnIdx);
// Expected data type.
if (dataType == typeof(Boolean))
return dbDataReader.GetBoolean(columnIdx);
LogAlternativeTypeColumn(columnName, typeof(Boolean), dataType);
}
return defaultValue;
}
public Byte GetFieldByte(DbDataReader dbDataReader, String columnName, Byte defaultValue)
{
return GetFieldByteNullable(dbDataReader, columnName, defaultValue) ?? defaultValue;
}
public Byte? GetFieldByteNullable(DbDataReader dbDataReader, String columnName, Byte? defaultValue)
{
int columnIdx = GetColumnOrdinal(dbDataReader, columnName);
if (columnIdx < 0) return defaultValue;
// Check for null value (to avoid throwing exception).
if (!dbDataReader.IsDBNull(columnIdx))
{
Type dataType = dbDataReader.GetFieldType(columnIdx);
// Expected data type.
if (dataType == typeof(Byte))
return dbDataReader.GetByte(columnIdx);
LogAlternativeTypeColumn(columnName, typeof(Byte), dataType);
}
return defaultValue;
}
public Int16 GetFieldInt16(DbDataReader dbDataReader, String columnName, Int16 defaultValue)
{
return GetFieldInt16Nullable(dbDataReader, columnName, defaultValue) ?? defaultValue;
}
public Int16? GetFieldInt16Nullable(DbDataReader dbDataReader, String columnName, Int16? defaultValue)
{
int columnIdx = GetColumnOrdinal(dbDataReader, columnName);
if (columnIdx < 0) return defaultValue;
// Check for null value (to avoid throwing exception).
if (!dbDataReader.IsDBNull(columnIdx))
{
Type dataType = dbDataReader.GetFieldType(columnIdx);
// Expected data type.
if (dataType == typeof(Int16))
return dbDataReader.GetInt16(columnIdx);
LogAlternativeTypeColumn(columnName, typeof(Int16), dataType);
}
return defaultValue;
}
public Int32 GetFieldInt32(DbDataReader dbDataReader, String columnName, Int32 defaultValue)
{
return GetFieldInt32Nullable(dbDataReader, columnName, defaultValue) ?? defaultValue;
}
public Int32? GetFieldInt32Nullable(DbDataReader dbDataReader, String columnName, Int32? defaultValue)
{
int columnIdx = GetColumnOrdinal(dbDataReader, columnName);
if (columnIdx < 0) return defaultValue;
// Check for null value (to avoid throwing exception).
if (!dbDataReader.IsDBNull(columnIdx))
{
Type dataType = dbDataReader.GetFieldType(columnIdx);
// Expected data type.
if (dataType == typeof(Int32))
return dbDataReader.GetInt32(columnIdx);
LogAlternativeTypeColumn(columnName, typeof(Int32), dataType);
if (dataType == typeof(Int16))
return (Int32)dbDataReader.GetInt16(columnIdx);
}
return defaultValue;
}
public Int64 GetFieldInt64(DbDataReader dbDataReader, String columnName, Int64 defaultValue)
{
return GetFieldInt64Nullable(dbDataReader, columnName, defaultValue) ?? defaultValue;
}
public Int64? GetFieldInt64Nullable(DbDataReader dbDataReader, String columnName, Int64? defaultValue)
{
int columnIdx = GetColumnOrdinal(dbDataReader, columnName);
if (columnIdx < 0) return defaultValue;
// Check for null value (to avoid throwing exception).
if (!dbDataReader.IsDBNull(columnIdx))
{
Type dataType = dbDataReader.GetFieldType(columnIdx);
// Expected data type.
if (dataType == typeof(Int64))
return dbDataReader.GetInt64(columnIdx);
LogAlternativeTypeColumn(columnName, typeof(Int64), dataType);
if (dataType == typeof(Int32))
return (Int64)dbDataReader.GetInt32(columnIdx);
if (dataType == typeof(Int16))
return (Int64)dbDataReader.GetInt16(columnIdx);
}
return defaultValue;
}
public Single GetFieldSingle(DbDataReader dbDataReader, String columnName, Single defaultValue)
{
return GetFieldSingleNullable(dbDataReader, columnName, defaultValue) ?? defaultValue;
}
public Single? GetFieldSingleNullable(DbDataReader dbDataReader, String columnName, Single? defaultValue)
{
int columnIdx = GetColumnOrdinal(dbDataReader, columnName);
if (columnIdx < 0) return defaultValue;
// Check for null value (to avoid throwing exception).
if (!dbDataReader.IsDBNull(columnIdx))
{
Type dataType = dbDataReader.GetFieldType(columnIdx);
// Expected data type.
if (dataType == typeof(Single))
return dbDataReader.GetFloat(columnIdx);
LogAlternativeTypeColumn(columnName, typeof(Single), dataType);
}
return defaultValue;
}
public Double GetFieldDouble(DbDataReader dbDataReader, String columnName, Double defaultValue)
{
return GetFieldDoubleNullable(dbDataReader, columnName, defaultValue) ?? defaultValue;
}
public Double? GetFieldDoubleNullable(DbDataReader dbDataReader, String columnName, Double? defaultValue)
{
int columnIdx = GetColumnOrdinal(dbDataReader, columnName);
if (columnIdx < 0) return defaultValue;
// Check for null value (to avoid throwing exception).
if (!dbDataReader.IsDBNull(columnIdx))
{
Type dataType = dbDataReader.GetFieldType(columnIdx);
// Expected data type.
if (dataType == typeof(Double))
return dbDataReader.GetDouble(columnIdx);
LogAlternativeTypeColumn(columnName, typeof(Double), dataType);
if (dataType == typeof(decimal))
return (double)dbDataReader.GetDecimal(columnIdx);
if (dataType == typeof(float))
return (double)dbDataReader.GetFloat(columnIdx);
}
return defaultValue;
}
public Decimal GetFieldDecimal(DbDataReader dbDataReader, String columnName, Decimal defaultValue)
{
return GetFieldDecimalNullable(dbDataReader, columnName, defaultValue) ?? defaultValue;
}
public Decimal? GetFieldDecimalNullable(DbDataReader dbDataReader, String columnName, Decimal? defaultValue = null)
{
int columnIdx = GetColumnOrdinal(dbDataReader, columnName);
if (columnIdx < 0) return defaultValue;
// Check for null value (to avoid throwing exception).
if (!dbDataReader.IsDBNull(columnIdx))
{
// Decimal data values may be alternative data types in result set.
// Avoid using try/catch as failures automatically log cast exceptions.
// Attempt to read value as decimal.
Type dataType = dbDataReader.GetFieldType(columnIdx);
// Expected data type.
if (dataType == typeof(Decimal))
return dbDataReader.GetDecimal(columnIdx);
LogAlternativeTypeColumn(columnName, typeof(Decimal), dataType);
// Allow 'double' value.
if (dataType == typeof(double))
return (decimal)dbDataReader.GetDouble(columnIdx);
// Allow 'float' value.
if (dataType == typeof(float))
return (decimal)dbDataReader.GetFloat(columnIdx);
}
return defaultValue;
}
public DateTime GetFieldDateTime(DbDataReader dbDataReader, String columnName, DateTime defaultValue)
{
return GetFieldDateTimeNullable(dbDataReader, columnName, defaultValue) ?? defaultValue;
}
public DateTime? GetFieldDateTimeNullable(DbDataReader dbDataReader, String columnName, DateTime? defaultValue)
{
int columnIdx = GetColumnOrdinal(dbDataReader, columnName);
if (columnIdx < 0) return defaultValue;
// Check for null value (to avoid throwing exception).
if (!dbDataReader.IsDBNull(columnIdx))
{
Type dataType = dbDataReader.GetFieldType(columnIdx);
// Expected data type.
if (dataType == typeof(DateTime))
return dbDataReader.GetDateTime(columnIdx);
LogAlternativeTypeColumn(columnName, typeof(DateTime), dataType);
}
return defaultValue;
}
public Guid GetFieldGuid(DbDataReader dbDataReader, String columnName, Guid defaultValue)
{
int columnIdx = GetColumnOrdinal(dbDataReader, columnName);
if (columnIdx < 0) return defaultValue;
// Check for null value (to avoid throwing exception).
if (!dbDataReader.IsDBNull(columnIdx))
{
Type dataType = dbDataReader.GetFieldType(columnIdx);
// Expected data type.
object data = dbDataReader[columnIdx];
if (data is Guid)
return (Guid)data;
LogAlternativeTypeColumn(columnName, typeof(Byte[]), dataType);
}
return defaultValue;
}
public byte[] GetFieldByteArray(DbDataReader dbDataReader, String columnName, byte[] defaultValue)
{
int columnIdx = GetColumnOrdinal(dbDataReader, columnName);
if (columnIdx < 0) return defaultValue;
// Check for null value (to avoid throwing exception).
if (!dbDataReader.IsDBNull(columnIdx))
{
Type dataType = dbDataReader.GetFieldType(columnIdx);
// Expected data type.
object data = dbDataReader[columnIdx];
if (data is byte[])
return (byte[])data;
LogAlternativeTypeColumn(columnName, typeof(Byte[]), dataType);
}
return defaultValue;
}
//-------------------------------------------------------------------
// Populate command parameters.
// Value is passed as a Typed parameter (rather than object) so that it's type is known
// even if the value is null, eg. to assign Db type for correct handling of null values,
// ref. byte[] -> VarBinary.
protected void AddCommandParameter<ValueType>(DbCommand dbCommand, String parameterName, ValueType value)
{
DbParameter dbParameter = dbCommand.CreateParameter();
dbParameter.ParameterName = parameterName;
dbParameter.Value = (Object)value ?? DBNull.Value;
if (typeof(ValueType) == typeof(Int16) || typeof(ValueType) == typeof(Int16?))
{
dbParameter.DbType = System.Data.DbType.Int16;
}
else if (typeof(ValueType) == typeof(Int32) || typeof(ValueType) == typeof(Int32?))
{
dbParameter.DbType = System.Data.DbType.Int32;
}
else if (typeof(ValueType) == typeof(DateTime) || typeof(ValueType) == typeof(DateTime?))
{
if (dbCommand is SqlCommand)
dbParameter.DbType = System.Data.DbType.DateTime2;
else dbParameter.DbType = System.Data.DbType.DateTime;
if ((Object)value == null || (DateTime)(Object)value == DateTime.MinValue || (DateTime)(Object)value == DateTime.MaxValue)
dbParameter.Value = DBNull.Value;
else
{
DateTime dateTime = (DateTime)dbParameter.Value;
// Resolve millisecond precision inconsistency between c# and odbc/sql.
//dbParameter.Value = new SqlDateTime((DateTime)dbParameter.Value);
dbParameter.Value = dateTime.AddMilliseconds(-dateTime.Millisecond);
// .Net 4.5
//dbParameter.Scale = 3;
}
}
else if (typeof(ValueType) == typeof(byte[]))
{
// Must be explicit with column type to handle null values correctly.
dbParameter.DbType = System.Data.DbType.Binary;
}
dbCommand.Parameters.Add(dbParameter);
}
//-------------------------------------------------------------------
// Database updates via ODBC Command.
public abstract bool ExecuteInsertCommand(DbCommand dbCommand);
public virtual bool ExecuteUpdateCommand(DbCommand dbCommand)
{
return ExecuteUpdateCommand(dbCommand, null);
}
public virtual bool ExecuteUpdateCommand(DbCommand dbCommand, List<String> columns = null)
{
throw new NotImplementedException($"ExecuteUpdateCommand(dbCmd,cols) not overridden. [{GetType().Name}]");
}
//public abstract bool ExecuteDeleteCommand (DbCommand dbCommand);
//-------------------------------------------------------------------
// Full list of all columns missing from database over life of application.
private static readonly List<String> columnsMissing = new List<string>();
// Missing columns are only logged on their initial discovery.
private void LogMissingColumn(String columnName)
{
String columnIdentifier = DbInfo.Context + "." + (!StringUtil.IsEmpty(SchemaName) ? SchemaName + "." : "") + TableName + "." + columnName;
if (!columnsMissing.ContainsCI(columnIdentifier))
{
columnsMissing.Add(columnIdentifier);
// Message is only logged on first occurence.
SaLogger.Debug(GetType().Name + " Column not found on database: " + columnIdentifier);
}
}
//-------------------------------------------------------------------
// Full list of all columns found with alternative data type in database over life of application.
private static readonly List<String> columnsAlternativeType = new List<string>();
// Missing columns are only logged on their initial discovery.
private void LogAlternativeTypeColumn(String columnName, Type typeExpected, Type typeFound)
{
String columnIdentifier = DbInfo.Context + "." + (!StringUtil.IsEmpty(SchemaName) ? SchemaName + "." : "") + TableName + "." + columnName;
if (!columnsAlternativeType.ContainsCI(columnIdentifier))
{
columnsAlternativeType.Add(columnIdentifier);
// Message is only logged on first occurence.
SaLogger.Debug(GetType().Name + " Column has inconsistent type: " + columnIdentifier + ". Expected: " + typeExpected.Name + ". Found: " + typeFound.Name);
}
}
//-------------------------------------------------------------------
// Logging.
public static SaMessageLevel LoggingLevel { get; set; } = SaMessageLevel.None;
public static String LoggingPrefix { get; set; } = " ~~~ ";
protected void Log(String fn, String message, SaMessageLevel level = SaMessageLevel.Debug)
{
if ((int)level > (int)LoggingLevel) return;
SaLogger.Log((fn + "\n\t" + message).Trim(), level);
}
//-------------------------------------------------------------------
}
//=======================================================================
}