ZhiYeJianKang_PeiXun/cyqdata-master/SQL/Schema/TableSchema.cs

1231 lines
61 KiB
C#
Raw Normal View History

2025-02-20 15:41:53 +08:00
using CYQ.Data.Orm;
using CYQ.Data.Table;
using CYQ.Data.Tool;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.OleDb;
using System.IO;
using System.Reflection;
namespace CYQ.Data.SQL
{
/// <summary>
/// 管理表(字段结构)
/// </summary>
internal partial class TableSchema
{
/// <summary>
/// 全局缓存实体类的表结构仅会对Type读取的结构
/// </summary>
private static MDictionary<string, MDataColumn> _ColumnCache = new MDictionary<string, MDataColumn>(StringComparer.OrdinalIgnoreCase);
public static MDataColumn GetColumns(string tableName, string conn)
{
return GetColumns(tableName, conn, false);
}
public static MDataColumn GetColumns(string tableName, string conn, bool isIgnoreCache)
{
//先修正Conn否则之前的key和修正后的key对不上。
string fixName;
conn = CrossDB.GetConn(tableName, out fixName, conn ?? AppConfig.DB.DefaultConn);
tableName = fixName;
if (conn == null)
{
return null;
}
string key = GetSchemaKey(tableName, conn);
#region
if (_ColumnCache.ContainsKey(key))
{
if (isIgnoreCache)
{
_ColumnCache.Remove(key);
}
else
{
return _ColumnCache[key].Clone();
}
}
if (!isIgnoreCache)
{
if (!string.IsNullOrEmpty(AppConfig.DB.SchemaMapPath))
{
string fullPath = GetSchemaFile(key);
if (System.IO.File.Exists(fullPath))
{
MDataColumn columns = MDataColumn.CreateFrom(fullPath);
if (columns.Count > 0)
{
_ColumnCache.Add(key, columns.Clone());
return columns;
}
}
}
}
#endregion
MDataColumn mdcs = null;
bool isTxtDB = false;
using (DalBase dbHelper = DalCreate.CreateDal(conn))
{
DataBaseType dalType = dbHelper.DataBaseType;
isTxtDB = dalType == DataBaseType.Txt || dalType == DataBaseType.Xml;
if (isTxtDB)
{
#region
if (!tableName.Contains(" "))// || tableName.IndexOfAny(Path.GetInvalidPathChars()) == -1
{
tableName = SqlFormat.NotKeyword(tableName);//处理database..tableName;
tableName = Path.GetFileNameWithoutExtension(tableName);//视图表,带“.“的,会出问题
string fileName = dbHelper.Con.DataSource + tableName + (dalType == DataBaseType.Txt ? ".txt" : ".xml");
mdcs = MDataColumn.CreateFrom(fileName);
mdcs.DataBaseType = dalType;
mdcs.DataBaseVersion = dbHelper.Version;
mdcs.Conn = conn;
}
#endregion
}
else
{
#region
mdcs = new MDataColumn();
mdcs.Conn = conn;
mdcs.TableName = tableName;
mdcs.DataBaseType = dalType;
mdcs.DataBaseVersion = dbHelper.Version;
tableName = SqlFormat.Keyword(tableName, dbHelper.DataBaseType);//加上关键字:引号,并转大小写。
string noKeywordTableName = SqlFormat.NotKeyword(tableName);//进行去关键字。
//如果table和helper不在同一个库
DalBase helper = dbHelper.ResetDalBase(tableName);
helper.IsRecordDebugInfo = false || AppDebug.IsContainSysSql;//内部系统不记录SQL表结构语句。
try
{
bool isView = tableName.Contains(" ");//是否视图。
if (!isView)
{
isView = CrossDB.Exists(noKeywordTableName, "V", conn);
}
if (!isView)
{
TableInfo info = CrossDB.GetTableInfoByName(noKeywordTableName, conn);//先查缓存
if (info != null)
{
mdcs.Description = info.Description;
}
else
{
Dictionary<string, string> tables = helper.GetTables();
if (tables.ContainsKey(noKeywordTableName))
{
mdcs.Description = tables[noKeywordTableName];
}
}
}
MCellStruct mStruct = null;
SqlDbType sqlType = SqlDbType.NVarChar;
if (isView)
{
string sqlText = SqlFormat.BuildSqlWithWhereOneEqualsTow(tableName);// string.Format("select * from {0} where 1=2", tableName);
mdcs = GetViewColumns(sqlText, ref helper);
if (mdcs != null && mdcs.Count > 0)
{
#region
Dictionary<string, MDataColumn> dic = new Dictionary<string, MDataColumn>();
MDataColumn temp;
for (int i = 0; i < mdcs.Count; i++)
{
MCellStruct cell = mdcs[i];
if (string.IsNullOrEmpty(cell.Description) && !string.IsNullOrEmpty(cell.TableName) && string.Compare(cell.TableName, noKeywordTableName, true) != 0)
{
if (!dic.ContainsKey(cell.TableName))
{
temp = GetColumns(cell.TableName, conn);
dic.Add(cell.TableName, temp);
}
else
{
temp = dic[cell.TableName];
}
if (temp != null && temp.Contains(cell.ColumnName))
{
cell.Description = temp[cell.ColumnName].Description;
}
}
}
dic.Clear();
dic = null;
#endregion
}
}
else
{
mdcs.AddRelateionTableName(noKeywordTableName);
switch (dalType)
{
case DataBaseType.MsSql:
case DataBaseType.Oracle:
case DataBaseType.MySql:
case DataBaseType.Sybase:
case DataBaseType.PostgreSQL:
case DataBaseType.DB2:
case DataBaseType.FireBird:
case DataBaseType.DaMeng:
case DataBaseType.KingBaseES:
#region Sql
string sql = string.Empty;
if (dalType == DataBaseType.MsSql)
{
#region Mssql
string dbName = null;
if (!helper.Version.StartsWith("08"))
{
//先获取同义词,检测是否跨库
string realTableName = Convert.ToString(helper.ExeScalar(string.Format(MSSQL_SynonymsName, noKeywordTableName), false));
if (!string.IsNullOrEmpty(realTableName))
{
string[] items = realTableName.Split('.');
noKeywordTableName = realTableName;
if (items.Length > 0)//跨库了
{
dbName = realTableName.Split('.')[0];
}
}
}
sql = GetMSSQLColumns(helper.Version.StartsWith("08"), dbName ?? helper.DataBaseName);
#endregion
}
else if (dalType == DataBaseType.MySql)
{
sql = GetMySqlColumns(helper.DataBaseName);
}
else if (dalType == DataBaseType.Oracle)
{
//先获取同义词,不检测是否跨库
string realTableName = Convert.ToString(helper.ExeScalar(string.Format(Oracle_SynonymsName, noKeywordTableName), false));
if (!string.IsNullOrEmpty(realTableName))
{
noKeywordTableName = realTableName;
}
sql = GetOracleColumns();
}
else if (dalType == DataBaseType.Sybase)
{
// tableName = SqlFormat.NotKeyword(tableName);
sql = GetSybaseColumns();
}
else if (dalType == DataBaseType.PostgreSQL)
{
sql = GetPostgreColumns(float.Parse(dbHelper.Version));
}
else if (dalType == DataBaseType.DB2)
{
//tableName = SqlFormat.NotKeyword(tableName).ToUpper();
sql = GetDB2Columns();
}
else if (dalType == DataBaseType.FireBird)
{
//tableName = SqlFormat.NotKeyword(tableName).ToUpper();
sql = GetFireBirdColumns();
}
else if (dalType == DataBaseType.DaMeng)
{
//tableName = SqlFormat.NotKeyword(tableName).ToUpper();
sql = GetDaMengColumns(helper.SchemaName);
}
else if (dalType == DataBaseType.KingBaseES)
{
//tableName = SqlFormat.NotKeyword(tableName).ToUpper();
sql = GetKingBaseESColumns(helper.SchemaName);
}
helper.AddParameters("TableName", noKeywordTableName, DbType.String, 150, ParameterDirection.Input);
DbDataReader sdr = helper.ExeDataReader(sql, false);
if (sdr != null)
{
long maxLength;
bool isAutoIncrement = false;
short scale = 0;
string sqlTypeName = string.Empty;
while (sdr.Read())
{
short.TryParse(Convert.ToString(sdr["Scale"]), out scale);
if (!long.TryParse(Convert.ToString(sdr["MaxSize"]), out maxLength))//mysql的长度可能大于int.MaxValue
{
maxLength = -1;
}
else if (maxLength > int.MaxValue)
{
maxLength = int.MaxValue;
}
sqlTypeName = Convert.ToString(sdr["SqlType"]).Trim();
sqlType = DataType.GetSqlType(sqlTypeName);
isAutoIncrement = Convert.ToBoolean(sdr["IsAutoIncrement"]);
mStruct = new MCellStruct(mdcs.DataBaseType);
mStruct.ColumnName = Convert.ToString(sdr["ColumnName"]).Trim();
mStruct.OldName = mStruct.ColumnName;
mStruct.SqlType = sqlType;
mStruct.IsAutoIncrement = isAutoIncrement;
mStruct.IsCanNull = Convert.ToBoolean(sdr["IsNullable"]);
mStruct.MaxSize = (int)maxLength;
mStruct.Scale = scale;
mStruct.Description = Convert.ToString(sdr["Description"]);
mStruct.DefaultValue = SqlFormat.FormatDefaultValue(dalType, sdr["DefaultValue"], 0, sqlType);
mStruct.IsPrimaryKey = Convert.ToString(sdr["IsPrimaryKey"]) == "1";
switch (dalType)
{
case DataBaseType.MsSql:
case DataBaseType.MySql:
case DataBaseType.Oracle:
mStruct.IsUniqueKey = Convert.ToString(sdr["IsUniqueKey"]) == "1";
mStruct.IsForeignKey = Convert.ToString(sdr["IsForeignKey"]) == "1";
mStruct.FKTableName = Convert.ToString(sdr["FKTableName"]);
break;
case DataBaseType.FireBird:
case DataBaseType.DaMeng:
case DataBaseType.KingBaseES:
mStruct.IsUniqueKey = Convert.ToString(sdr["IsUniqueKey"]) == "1";
break;
}
mStruct.SqlTypeName = sqlTypeName;
mStruct.TableName = noKeywordTableName;
mdcs.Add(mStruct);
}
sdr.Close();
if (dalType == DataBaseType.Oracle && mdcs.Count > 0)//默认没有自增概念,只能根据情况判断。
{
MCellStruct firstColumn = mdcs[0];
if (firstColumn.IsPrimaryKey && firstColumn.ColumnName.ToLower().Contains("id") && firstColumn.Scale == 0 && DataType.GetGroup(firstColumn.SqlType) == DataGroupType.Number && mdcs.JointPrimary.Count == 1)
{
firstColumn.IsAutoIncrement = true;
}
}
}
#endregion
break;
case DataBaseType.SQLite:
#region SQlite
if (helper.Con.State != ConnectionState.Open)
{
helper.Con.Open();
}
DataTable sqliteDt = helper.Con.GetSchema("Columns", new string[] { null, null, noKeywordTableName });
if (!helper.IsOpenTrans)
{
helper.Con.Close();
}
int size;
short sizeScale;
string dataTypeName = string.Empty;
foreach (DataRow row in sqliteDt.Rows)
{
object len = row["NUMERIC_PRECISION"];
if (len == null || len == DBNull.Value)
{
len = row["CHARACTER_MAXIMUM_LENGTH"];
}
short.TryParse(Convert.ToString(row["NUMERIC_SCALE"]), out sizeScale);
if (!int.TryParse(Convert.ToString(len), out size))//mysql的长度可能大于int.MaxValue
{
size = -1;
}
dataTypeName = Convert.ToString(row["DATA_TYPE"]);
if (dataTypeName == "text" && size > 0)
{
sqlType = DataType.GetSqlType("varchar");
}
else
{
sqlType = DataType.GetSqlType(dataTypeName);
}
//COLUMN_NAME,DATA_TYPE,PRIMARY_KEY,IS_NULLABLE,CHARACTER_MAXIMUM_LENGTH AUTOINCREMENT
mStruct = new MCellStruct(row["COLUMN_NAME"].ToString(), sqlType, Convert.ToBoolean(row["AUTOINCREMENT"]), Convert.ToBoolean(row["IS_NULLABLE"]), size);
mStruct.Scale = sizeScale;
mStruct.Description = Convert.ToString(row["DESCRIPTION"]);
mStruct.DefaultValue = SqlFormat.FormatDefaultValue(dalType, row["COLUMN_DEFAULT"], 0, sqlType);//"COLUMN_DEFAULT"
mStruct.IsPrimaryKey = Convert.ToBoolean(row["PRIMARY_KEY"]);
mStruct.SqlTypeName = dataTypeName;
mStruct.TableName = noKeywordTableName;
mdcs.Add(mStruct);
}
#endregion
break;
case DataBaseType.Access:
case DataBaseType.Excel:
case DataBaseType.FoxPro:
#region Access
DataTable keyDt, valueDt;
string sqlText = SqlFormat.BuildSqlWithWhereOneEqualsTow(tableName);// string.Format("select * from {0} where 1=2", tableName);
OleDbConnection con = new OleDbConnection(helper.Con.ConnectionString);
OleDbCommand com = new OleDbCommand(sqlText, con);
con.Open();
keyDt = com.ExecuteReader(CommandBehavior.KeyInfo).GetSchemaTable();
valueDt = con.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new object[] { null, null, noKeywordTableName });
con.Close();
con.Dispose();
if (keyDt != null && valueDt != null)
{
string columnName = string.Empty, sqlTypeName = string.Empty;
bool isKey = false, isCanNull = true, isAutoIncrement = false;
int maxSize = -1;
short maxSizeScale = 0;
SqlDbType sqlDbType;
foreach (DataRow row in keyDt.Rows)
{
columnName = row["ColumnName"].ToString();
isKey = Convert.ToBoolean(row["IsKey"]);//IsKey
isCanNull = Convert.ToBoolean(row["AllowDBNull"]);//AllowDBNull
isAutoIncrement = Convert.ToBoolean(row["IsAutoIncrement"]);
sqlTypeName = Convert.ToString(row["DataType"]);
sqlDbType = DataType.GetSqlType(sqlTypeName);
short.TryParse(Convert.ToString(row["NumericScale"]), out maxSizeScale);
if (Convert.ToInt32(row["NumericPrecision"]) > 0)//NumericPrecision
{
maxSize = Convert.ToInt32(row["NumericPrecision"]);
}
else
{
long len = Convert.ToInt64(row["ColumnSize"]);
if (len > int.MaxValue)
{
maxSize = int.MaxValue;
}
else
{
maxSize = (int)len;
}
}
mStruct = new MCellStruct(columnName, sqlDbType, isAutoIncrement, isCanNull, maxSize);
mStruct.Scale = maxSizeScale;
mStruct.IsPrimaryKey = isKey;
mStruct.SqlTypeName = sqlTypeName;
mStruct.TableName = noKeywordTableName;
foreach (DataRow item in valueDt.Rows)
{
if (columnName == item[3].ToString())//COLUMN_NAME
{
if (item[8].ToString() != "")
{
mStruct.DefaultValue = SqlFormat.FormatDefaultValue(dalType, item[8], 0, sqlDbType);//"COLUMN_DEFAULT"
}
break;
}
}
mdcs.Add(mStruct);
}
}
#endregion
break;
}
}
}
catch (Exception err)
{
Log.Write(err, LogType.DataBase);
//helper.DebugInfo.Append(err.Message);
}
#endregion
}
}
if (mdcs != null && mdcs.Count > 0)
{
//移除被标志的列:
string[] fields = AppConfig.DB.HiddenFields.Split(',');
foreach (string item in fields)
{
string field = item.Trim();
if (!string.IsNullOrEmpty(field) & mdcs.Contains(field))
{
mdcs.Remove(field);
}
}
#region
if (mdcs.Count > 0)
{
if (!isTxtDB && !string.IsNullOrEmpty(AppConfig.DB.SchemaMapPath))
{
string path = GetSchemaFile(key);
mdcs.WriteSchema(path);
}
else if (!_ColumnCache.ContainsKey(key))
{
_ColumnCache.Add(key, mdcs.Clone());
}
}
#endregion
}
return mdcs;
}
private static MDataColumn GetViewColumns(string sqlText, ref DalBase helper)
{
MDataColumn mdc = null;
helper.OpenCon(null, AllowConnLevel.MaterBackupSlave);
helper.Com.CommandText = sqlText;
DbDataReader sdr = helper.Com.ExecuteReader(CommandBehavior.KeyInfo);
DataTable keyDt = null;
if (sdr != null)
{
keyDt = sdr.GetSchemaTable();
mdc = GetColumnByTable(keyDt, sdr, true);
mdc.DataBaseType = helper.DataBaseType;
mdc.DataBaseVersion = helper.Version;
}
return mdc;
}
/// <summary>
/// 清空对应表的缓存
/// </summary>
/// <param name="tableName"></param>
/// <param name="conn"></param>
public static void Remove(string tableName, string conn)
{
string key = GetSchemaKey(tableName, conn);
Remove(key);
}
/// <summary>
/// 清空缓存
/// </summary>
/// <param name="key"></param>
public static void Remove(string key)
{
_ColumnCache.Remove(key);
if (!string.IsNullOrEmpty(AppConfig.DB.SchemaMapPath))
{
string path = GetSchemaFile(key);
IOHelper.Delete(path);
}
}
public static void Clear()
{
_ColumnCache.Clear();
}
}
internal partial class TableSchema
{
#region
// private static CacheManage _SchemaCache = CacheManage.Instance;//Cache操作
internal static bool FillTableSchema(ref MDataRow row, string tableName, string sourceTableName)
{
MDataColumn mdcs = GetColumns(tableName, row.Conn);
if (mdcs == null || mdcs.Count == 0)
{
return false;
}
row = mdcs.ToRow(sourceTableName);
return true;
}
/// <summary>
/// 获取表结构Key*.txt
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
internal static string GetSchemaFile(string key)
{
string folderPath = AppConfig.WebRootPath + AppConfig.DB.SchemaMapPath.Trim('/', '\\');
if (!System.IO.Directory.Exists(folderPath))
{
System.IO.Directory.CreateDirectory(folderPath);
}
return folderPath + "/" + key + ".ts";
}
/// <summary>
/// 缓存表架构Key
/// </summary>
internal static string GetSchemaKey(string tableName, string conn)
{
tableName = SqlFormat.NotKeyword(tableName);//xxx..[TTTT]
if (string.IsNullOrEmpty(conn))
{
conn = CrossDB.GetConn(tableName, out tableName, conn);//[TTTT]
}
tableName = SqlFormat.NotKeyword(tableName);
return ConnBean.GetHashKey(conn) + "/" + GetKey(tableName) + "_" + TableInfo.GetHashKey(tableName);
}
private static string GetKey(string tableName)
{
if (string.IsNullOrEmpty(tableName)) { return tableName; }
int i = tableName.LastIndexOf(')');
string pre = "T_";
if (i > 0)
{
tableName = tableName.Substring(i + 1);
pre = "S_";
}
if (tableName.StartsWith("V_"))
{
pre = "V_";
}
else if (tableName.StartsWith("P_"))
{
pre = "P_";
}
tableName = pre + tableName.Replace("-", "").Replace("_", "").Replace(".", "").Replace("*", "").Replace(" ", "");
//if (i > 0)
//{
// tableName = "S_" + tableName;//sql
//}
//else
//{
// tableName = "T_" + tableName;//table
//}
if (tableName.Length > 30)
{
return tableName.Substring(0, 30);
}
return tableName;
}
// private static bool FillSchemaFromCache(ref MDataRow row, string tableName, string sourceTableName)
// {
// bool returnResult = false;
// string key = GetSchemaKey(tableName, row.Conn);
// if (CacheManage.LocalInstance.Contains(key))//缓存里获取
// {
// try
// {
// row = ((MDataColumn)CacheManage.LocalInstance.Get(key)).ToRow(sourceTableName);
// returnResult = row.Count > 0;
// }
// catch (Exception err)
// {
// Log.Write(err, LogType.DataBase);
// }
// }
// else if (!string.IsNullOrEmpty(AppConfig.DB.SchemaMapPath))
// {
// string fullPath = AppConfig.RunPath + AppConfig.DB.SchemaMapPath + key + ".ts";
// if (System.IO.File.Exists(fullPath))
// {
// MDataColumn mdcs = MDataColumn.CreateFrom(fullPath);
// if (mdcs.Count > 0)
// {
// row = mdcs.ToRow(sourceTableName);
// returnResult = row.Count > 0;
// CacheManage.LocalInstance.Set(key, mdcs.Clone(), 1440);
// }
// }
// }
// return returnResult;
// }
// private static bool FillSchemaFromDb(ref MDataRow row, string tableName, string sourceTableName)
// {
// try
// {
// MDataColumn mdcs = TableSchema.GetColumns(tableName, row.Conn);
// if (mdcs == null || mdcs.Count == 0)
// {
// return false;
// }
// row = mdcs.ToRow(sourceTableName);
// string key = GetSchemaKey(tableName, mdcs.Conn);
// CacheManage.LocalInstance.Set(key, mdcs.Clone(), 1440);
// if (!string.IsNullOrEmpty(AppConfig.DB.SchemaMapPath))
// {
// string folderPath = AppConfig.RunPath + AppConfig.DB.SchemaMapPath;
// if (!System.IO.Directory.Exists(folderPath))
// {
// System.IO.Directory.CreateDirectory(folderPath);
// }
// mdcs.WriteSchema(folderPath + key + ".ts");
// }
// return true;
// }
// catch (Exception err)
// {
// Log.Write(err, LogType.DataBase);
// return false;
// }
// }
#endregion
}
/// <summary>
/// 从实体转成列
/// </summary>
internal partial class TableSchema
{
public static MDataColumn GetColumnByType(Type typeInfo)
{
return GetColumnByType(typeInfo, null);
}
public static MDataColumn GetColumnByType(Type typeInfo, string conn)
{
if (typeInfo == null) { return null; }
string key = "ColumnsCache_" + typeInfo.FullName;
if (_ColumnCache.ContainsKey(key))
{
return _ColumnCache[key].Clone();
}
else
{
MDataColumn mdc = GetColumns(typeInfo);
if (!_ColumnCache.ContainsKey(key))
{
_ColumnCache.Set(key, mdc);
}
string outConn;
string tableName = DBFast.GetTableName(typeInfo, out outConn);
if (!string.IsNullOrEmpty(tableName) && (!string.IsNullOrEmpty(conn) || !string.IsNullOrEmpty(outConn)))
{
key = GetSchemaKey(tableName, outConn ?? conn);
//如果是刚创建表的情况,存档多一份
if (!_ColumnCache.ContainsKey(key))
{
_ColumnCache.Set(key, mdc);
}
}
return mdc.Clone();
}
}
private static MDataColumn GetColumns(Type typeInfo)
{
MDataColumn mdc = new MDataColumn();
mdc.TableName = typeInfo.Name;
SysType st = ReflectTool.GetSystemType(ref typeInfo);
switch (st)
{
case SysType.Base:
case SysType.Enum:
mdc.Add(typeInfo.Name, DataType.GetSqlType(typeInfo), false);
return mdc;
case SysType.Generic:
case SysType.Collection:
Type[] argTypes;
Tool.ReflectTool.GetArgumentLength(ref typeInfo, out argTypes);
if (argTypes.Length == 2)
{
if (st == SysType.Collection)
{
mdc.Add("Name", DataType.GetSqlType(argTypes[0]), false);
mdc.Add("Value", DataType.GetSqlType(argTypes[1]), false);
}
else
{
mdc.Add("Key", DataType.GetSqlType(argTypes[0]), false);
mdc.Add("Value", DataType.GetSqlType(argTypes[1]), false);
}
}
else
{
foreach (Type type in argTypes)
{
mdc.Add(type.Name, DataType.GetSqlType(type), false);
}
}
argTypes = null;
return mdc;
}
List<PropertyInfo> pis = ReflectTool.GetPropertyList(typeInfo);
if (pis.Count > 0)
{
for (int i = 0; i < pis.Count; i++)
{
SetStruct(mdc, pis[i], null, i, pis.Count);
}
}
List<FieldInfo> fis = ReflectTool.GetFieldList(typeInfo);
if (fis.Count > 0)
{
for (int i = 0; i < fis.Count; i++)
{
SetStruct(mdc, null, fis[i], i, fis.Count);
}
}
object[] tableAttr = typeInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);//看是否设置了表特性,获取表名和表描述
if (tableAttr != null && tableAttr.Length == 1)
{
DescriptionAttribute attr = tableAttr[0] as DescriptionAttribute;
if (attr != null && !string.IsNullOrEmpty(attr.Description))
{
mdc.Description = attr.Description;
}
}
pis = null;
return mdc;
}
private static void SetStruct(MDataColumn mdc, PropertyInfo pi, FieldInfo fi, int i, int count)
{
Type type = pi != null ? pi.PropertyType : fi.FieldType;
if (ReflectTool.ExistsAttr(AppConst.JsonIgnoreType, pi, fi))//获取Json忽略标识
{
return;//被Json忽略的列不在返回列结构中。
}
string name = pi != null ? pi.Name : fi.Name;
SqlDbType sqlType = SQL.DataType.GetSqlType(type);
if (type.IsEnum)
{
if (ReflectTool.ExistsAttr(AppConst.JsonEnumToStringType, pi, fi) || ReflectTool.ExistsAttr(AppConst.JsonEnumToDescriptionType, pi, fi))//获取Json忽略标识
{
sqlType = SqlDbType.NVarChar;
}
}
mdc.Add(name, sqlType);
MCellStruct column = mdc[mdc.Count - 1];
LengthAttribute la = ReflectTool.GetAttr<LengthAttribute>(pi, fi);//获取长度设置
if (la != null)
{
column.MaxSize = la.MaxSize;
column.Scale = la.Scale;
}
if (column.MaxSize <= 0)
{
column.MaxSize = DataType.GetMaxSize(sqlType);
}
KeyAttribute ka = ReflectTool.GetAttr<KeyAttribute>(pi, fi);//获取关键字判断
if (ka != null)
{
column.IsPrimaryKey = ka.IsPrimaryKey;
column.IsAutoIncrement = ka.IsAutoIncrement;
column.IsCanNull = ka.IsCanNull;
}
else if (i == 0)
{
column.IsPrimaryKey = true;
column.IsCanNull = false;
if (column.ColumnName.ToLower().Contains("id") && (column.SqlType == System.Data.SqlDbType.Int || column.SqlType == SqlDbType.BigInt))
{
column.IsAutoIncrement = true;
}
}
DefaultValueAttribute dva = ReflectTool.GetAttr<DefaultValueAttribute>(pi, fi);
if (dva != null && dva.DefaultValue != null)
{
if (column.SqlType == SqlDbType.Bit)
{
column.DefaultValue = (dva.DefaultValue.ToString() == "True" || dva.DefaultValue.ToString() == "1") ? 1 : 0;
}
else
{
column.DefaultValue = dva.DefaultValue;
}
}
else if (i > count - 3 && sqlType == SqlDbType.DateTime && name.EndsWith("Time"))
{
column.DefaultValue = SqlValue.GetDate;
}
DescriptionAttribute da = ReflectTool.GetAttr<DescriptionAttribute>(pi, fi);//看是否有字段描述属性。
if (da != null)
{
column.Description = da.Description;
}
}
}
/// <summary>
/// 从DataTable 架构转列
/// </summary>
internal partial class TableSchema
{
/// <summary>
/// DbDataReader的GetSchema拿到的DataType、Size、Scale很不靠谱
/// </summary>
private static void FixTableSchemaType(DataTable tableSchema, DbDataReader sdr, bool isCloseReader)
{
if (sdr != null)
{
if (tableSchema != null)
{
tableSchema.Columns.Add("DataTypeString");
for (int i = 0; i < sdr.FieldCount; i++)
{
tableSchema.Rows[i]["DataTypeString"] = sdr.GetDataTypeName(i);
}
}
if (isCloseReader)
{
sdr.Close();
}
}
}
internal static MDataColumn GetColumnByTable(DataTable tableSchema, DbDataReader sdr, bool isCloseReader)
{
FixTableSchemaType(tableSchema, sdr, isCloseReader);
MDataColumn mdcs = new MDataColumn();
if (tableSchema != null && tableSchema.Rows.Count > 0)
{
mdcs.TableName = tableSchema.TableName;
mdcs.isViewOwner = true;
string columnName = string.Empty, sqlTypeName = string.Empty, tableName = string.Empty;
bool isKey = false, isCanNull = true, isAutoIncrement = false;
int maxSize = -1;
short maxSizeScale = 0;
SqlDbType sqlDbType;
string dataTypeName = "DataTypeString";
if (!tableSchema.Columns.Contains(dataTypeName))
{
dataTypeName = "DataType";
if (!tableSchema.Columns.Contains(dataTypeName))
{
dataTypeName = "DataTypeName";
}
}
bool isHasAutoIncrement = tableSchema.Columns.Contains("IsAutoIncrement");
bool isHasHidden = tableSchema.Columns.Contains("IsHidden");
string hiddenFields = "," + AppConfig.DB.HiddenFields.ToLower() + ",";
for (int i = 0; i < tableSchema.Rows.Count; i++)
{
DataRow row = tableSchema.Rows[i];
tableName = Convert.ToString(row["BaseTableName"]);
mdcs.AddRelateionTableName(tableName);
if (isHasHidden && Convert.ToString(row["IsHidden"]) == "True")// !dcList.Contains(columnName))
{
continue;//后面那个会多出关联字段。
}
columnName = row["ColumnName"].ToString().Trim('"');//sqlite视图时会带引号
if (string.IsNullOrEmpty(columnName))
{
columnName = "Empty_" + i;
}
#region
bool isHiddenField = hiddenFields.IndexOf("," + columnName + ",", StringComparison.OrdinalIgnoreCase) > -1;
if (isHiddenField)
{
continue;
}
#endregion
bool.TryParse(Convert.ToString(row["IsKey"]), out isKey);
bool.TryParse(Convert.ToString(row["AllowDBNull"]), out isCanNull);
// isKey = Convert.ToBoolean();//IsKey
//isCanNull = Convert.ToBoolean(row["AllowDBNull"]);//AllowDBNull
if (isHasAutoIncrement)
{
isAutoIncrement = Convert.ToBoolean(row["IsAutoIncrement"]);
}
sqlTypeName = Convert.ToString(row[dataTypeName]);
sqlDbType = DataType.GetSqlType(sqlTypeName);
if (short.TryParse(Convert.ToString(row["NumericScale"]), out maxSizeScale) && maxSizeScale == 255)
{
maxSizeScale = 0;
}
if (!int.TryParse(Convert.ToString(row["NumericPrecision"]), out maxSize) || maxSize == 255)//NumericPrecision
{
long len;
if (long.TryParse(Convert.ToString(row["ColumnSize"]), out len))
{
if (len > int.MaxValue)
{
maxSize = int.MaxValue;
}
else
{
maxSize = (int)len;
}
}
}
MCellStruct mStruct = new MCellStruct(columnName, sqlDbType, isAutoIncrement, isCanNull, maxSize);
mStruct.Scale = maxSizeScale;
mStruct.IsPrimaryKey = isKey;
mStruct.SqlTypeName = sqlTypeName;
mStruct.TableName = tableName;
mStruct.OldName = mStruct.ColumnName;
mStruct.ReaderIndex = i;
if (sqlTypeName == "TINYINT")
{
switch (Convert.ToString(row["DataType"]))
{
case "System.SByte":
mStruct.valueType = typeof(System.SByte);
break;
case "System.Byte":
mStruct.valueType = typeof(System.Byte);
break;
case "System.Boolean":
mStruct.valueType = typeof(System.Boolean);
break;
}
}
mdcs.Add(mStruct);
}
tableSchema = null;
}
return mdcs;
}
}
internal partial class TableSchema
{
#region
private const string MSSQL_SynonymsName = "SELECT TOP 1 base_object_name from sys.synonyms WHERE NAME = '{0}'";
private const string Oracle_SynonymsName = "SELECT TABLE_NAME FROM USER_SYNONYMS WHERE SYNONYM_NAME='{0}' and rownum=1";
internal static string GetMSSQLColumns(bool for2000, string dbName)
{
// 2005以上增加同义词支持。 case s2.name WHEN 'timestamp' THEN 'variant' ELSE s2.name END as [SqlType],
return string.Format(@"select s1.name as ColumnName,case s2.name WHEN 'uniqueidentifier' THEN 36
WHEN 'ntext' THEN -1 WHEN 'text' THEN -1 WHEN 'image' THEN -1 else s1.[prec] end as [MaxSize],s1.scale as [Scale],
isnullable as [IsNullable],colstat&1 as [IsAutoIncrement],
case s2.name when 'timestamp' then 'b_timestamp' else s2.name end as [SqlType],
case when exists(SELECT 1 FROM {0}..sysobjects where xtype='PK' and name in (SELECT name FROM {0}..sysindexes WHERE id=s1.id and
indid in(SELECT indid FROM {0}..sysindexkeys WHERE id=s1.id AND colid=s1.colid))) then 1 else 0 end as [IsPrimaryKey],
case when exists(SELECT 1 FROM {0}..sysobjects where xtype='UQ' and name in (SELECT name FROM {0}..sysindexes WHERE id=s1.id and
indid in(SELECT indid FROM {0}..sysindexkeys WHERE id=s1.id AND colid=s1.colid))) then 1 else 0 end as [IsUniqueKey],
case when s5.rkey=s1.colid or s5.fkey=s1.colid then 1 else 0 end as [IsForeignKey],
case when s5.fkey=s1.colid then object_name(s5.rkeyid) else null end [FKTableName],
isnull(s3.text,'') as [DefaultValue],
s4.value as Description
from {0}..syscolumns s1 right join {0}..systypes s2 on s2.xtype =s1.xtype
left join {0}..syscomments s3 on s1.cdefault=s3.id " +
(for2000 ? "left join {0}..sysproperties s4 on s4.id=s1.id and s4.smallid=s1.colid " : "left join {0}.sys.extended_properties s4 on s4.major_id=s1.id and s4.minor_id=s1.colid")
+ " left join {0}..sysforeignkeys s5 on (s5.rkeyid=s1.id and s5.rkey=s1.colid) or (s5.fkeyid=s1.id and s5.fkey=s1.colid) where s1.id=object_id('{0}..'+@TableName) and s2.name<>'sysname' and s2.usertype<100 order by s1.colid", "[" + dbName + "]");
}
internal static string GetOracleColumns()
{
//同义词已被提取到外面执行,外部对表名已转大写,对语句进行了优化。
return @"select A.COLUMN_NAME as ColumnName,case DATA_TYPE when 'DATE' then 23 when 'CLOB' then 2147483647 when 'NCLOB' then 1073741823 else case when CHAR_COL_DECL_LENGTH is not null then CHAR_COL_DECL_LENGTH
else case when DATA_PRECISION is not null then DATA_PRECISION else DATA_LENGTH end end end as MaxSize,DATA_SCALE as Scale,
case NULLABLE when 'Y' then 1 else 0 end as IsNullable,
0 as IsAutoIncrement,
case when (DATA_TYPE='NUMBER' and DATA_SCALE>0 and DATA_PRECISION<13) then 'float'
when (DATA_TYPE='NUMBER' and DATA_SCALE>0 and DATA_PRECISION<22) then 'double'
when (DATA_TYPE='NUMBER' and DATA_SCALE=0 and DATA_PRECISION<11) then 'int'
when (DATA_TYPE='NUMBER' and DATA_SCALE=0 and DATA_PRECISION<20) then 'long'
when DATA_TYPE='NUMBER' then 'decimal'
else DATA_TYPE end as SqlType,
case when v.CONSTRAINT_TYPE='P' then 1 else 0 end as IsPrimaryKey,
case when v.CONSTRAINT_TYPE='U' then 1 else 0 end as IsUniqueKey,
case when v.CONSTRAINT_TYPE='R' then 1 else 0 end as IsForeignKey,
case when length(r_constraint_name)>1
then (select table_name from user_constraints s where s.constraint_name=v.r_constraint_name)
else null
end as FKTableName ,
data_default as DefaultValue,
COMMENTS AS Description
from USER_TAB_COLS A left join user_col_comments B on A.Table_Name = B.Table_Name and A.Column_Name = B.Column_Name
left join
(select uc1.table_name,ucc.column_name, uc1.constraint_type,uc1.r_constraint_name from user_constraints uc1
left join (SELECT column_name,constraint_name FROM user_cons_columns WHERE TABLE_NAME=:TableName) ucc on ucc.constraint_name=uc1.constraint_name
where uc1.constraint_type in('P','U','R') ) v
on A.TABLE_NAME=v.table_name and A.COLUMN_NAME=v.column_name
where A.TABLE_NAME=:TableName order by COLUMN_id";
// left join user_constraints uc2 on uc1.r_constraint_name=uc2.constraint_name
// where A.TABLE_NAME= nvl((SELECT TABLE_NAME FROM USER_SYNONYMS WHERE SYNONYM_NAME=UPPER(:TableName) and rownum=1),UPPER(:TableName)) order by COLUMN_id";
}
internal static string GetMySqlColumns(string dbName)
{
return string.Format(@"SELECT s1.COLUMN_NAME as ColumnName,case DATA_TYPE when 'int' then 10 when 'date' then 10 when 'time' then 8 when 'datetime' then 23 when 'year' then 4
else IFNULL(CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION) end as MaxSize,NUMERIC_SCALE as Scale,
case IS_NULLABLE when 'YES' then 1 else 0 end as IsNullable,
CASE extra when 'auto_increment' then 1 else 0 END AS IsAutoIncrement,
DATA_TYPE as SqlType,
case Column_key WHEN 'PRI' then 1 else 0 end as IsPrimaryKey,
case s3.CONSTRAINT_TYPE when 'UNIQUE' then 1 else 0 end as IsUniqueKey,
case s3.CONSTRAINT_TYPE when 'FOREIGN KEY' then 1 else 0 end as IsForeignKey,
s2.REFERENCED_TABLE_NAME as FKTableName,
COLUMN_DEFAULT AS DefaultValue,
COLUMN_COMMENT AS Description
FROM `information_schema`.`COLUMNS` s1
LEFT JOIN `information_schema`.KEY_COLUMN_USAGE s2 on s2.TABLE_SCHEMA=s1.TABLE_SCHEMA and s2.TABLE_NAME=s1.TABLE_NAME and s2.COLUMN_NAME=s1.COLUMN_NAME
LEFT JOIN `information_schema`.TABLE_CONSTRAINTS s3 on s3.TABLE_SCHEMA=s2.TABLE_SCHEMA and s3.TABLE_NAME=s2.TABLE_NAME and s3.CONSTRAINT_NAME=s2.CONSTRAINT_NAME
where s1.TABLE_SCHEMA='{0}' and s1.TABLE_NAME=?TableName order by s1.ORDINAL_POSITION", dbName);
}
internal static string GetSybaseColumns()
{
return @"select
s1.name as ColumnName,
s1.length as MaxSize,
s1.scale as Scale,
case s1.status&8 when 8 then 1 ELSE 0 END AS IsNullable,
case s1.status&128 when 128 then 1 ELSE 0 END as IsAutoIncrement,
case s2.name when 'timestamp' then 'b_timestamp' else s2.name end as SqlType,
case when exists(SELECT 1 FROM sysindexes WHERE id=s1.id AND s1.name=index_col(@TableName,indid,s1.colid)) then 1 else 0 end as IsPrimaryKey,
str_replace(s3.text,'DEFAULT ',null) as DefaultValue,
null as Description
from syscolumns s1 left join systypes s2 on s1.usertype=s2.usertype
left join syscomments s3 on s1.cdefault=s3.id
where s1.id =object_id(@TableName) and s2.usertype<100
order by s1.colid";
}
internal static string GetPostgreColumns(float version)
{
string key = "case when position('nextval' in column_default)>0 then 1 else 0 end";
if (version >= 10)
{
key = "case i.is_identity when 'NO' then 0 else 1 end";
}
return string.Format(@"select
a.attname AS ColumnName,
i.data_type AS SqlType,
coalesce(character_maximum_length,numeric_precision,-1) as MaxSize,numeric_scale as Scale,
case a.attnotnull when 'true' then 0 else 1 end AS IsNullable,
{0} as IsAutoIncrement,
case when o.conkey[a.attnum] is null then 0 else 1 end as IsPrimaryKey,
d.description AS Description,
i.column_default as DefaultValue
from pg_class c
left join pg_attribute a on c.oid=a.attrelid
left join pg_description d on a.attrelid=d.objoid AND a.attnum = d.objsubid
left join pg_type t on a.atttypid = t.oid
left join information_schema.columns i on i.table_schema='public' and i.table_name=c.relname and i.column_name=a.attname
left join pg_constraint o on o.contype='p' and o.conrelid=c.oid
where c.relname =:TableName
and a.attnum > 0 and a.atttypid>0
ORDER BY a.attnum", key);
}
internal static string GetDB2Columns()
{
return @"select a.colname as ColumnName ,
a.length as MaxSize,
a.typename as SqlType,
a.Scale,
case a.Nulls when 'Y' then 1 else 0 end AS IsNullable,
case a.keyseq when 1 then 1 ELSE 0 END as IsAutoIncrement,
case c.type when 'P' then 1 else 0 end as IsPrimaryKey,
case c.type when 'U' then 1 else 0 end as IsUniqueKey,
a.remarks as Description,
a.default as DefaultValue
from SYSCAT.COLUMNS a
left join syscat.keycoluse b on a.tabname=b.tabname and a.colname=b.colname
left join syscat.tabconst c on b.tabname=c.tabname and b.constname=c.constname
where a.tabname=@TableName
order by a.colno
";
}
internal static string GetFireBirdColumns()
{
return @"SELECT
RF.RDB$FIELD_NAME AS ColumnName,
CASE WHEN (FTY.RDB$TYPE_NAME='INT128' AND FLD.RDB$FIELD_SUB_TYPE>0) OR (FTY.RDB$TYPE_NAME IN('DECFLOAT(16)','DECFLOAT(34)')) THEN FLD.RDB$FIELD_PRECISION
WHEN FTY.RDB$TYPE_NAME IN('BLOB') THEN FLD.RDB$SEGMENT_LENGTH
ELSE FLD.RDB$FIELD_LENGTH END AS MaxSize,
CASE when (FLD.RDB$FIELD_SUB_TYPE=1 AND FTY.RDB$TYPE_NAME='INT128') THEN 'NUMERIC'
when (FLD.RDB$FIELD_SUB_TYPE=2 AND FTY.RDB$TYPE_NAME='INT128') THEN 'DECIMAL'
when (FLD.RDB$FIELD_SUB_TYPE=0 AND FTY.RDB$TYPE_NAME='BLOB') then 'BINARY'
when (FLD.RDB$FIELD_SUB_TYPE=1 AND FTY.RDB$TYPE_NAME='BLOB') then 'TEXT'
when FTY.RDB$TYPE_NAME='SHORT' then 'SMALLINT'
when FTY.RDB$TYPE_NAME='LONG' then 'INTEGER'
when FTY.RDB$TYPE_NAME='INT64' then 'BIGINT'
when FTY.RDB$TYPE_NAME='TEXT' then 'CHAR'
when FTY.RDB$TYPE_NAME='VARYING' then 'VARCHAR'
else FTY.RDB$TYPE_NAME end AS SqlType,
ABS(FLD.RDB$FIELD_SCALE) AS Scale,
CASE RF.RDB$NULL_FLAG when 1 then 0 ELSE 1 END AS IsNullable,
RF.RDB$DEFAULT_SOURCE AS DefaultValue,
CASE
WHEN IIF(V.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY', 1, 0) = 1 THEN 1
ELSE 0
END AS IsPrimaryKey,
case RF.RDB$IDENTITY_TYPE when 1 then 1 ELSE 0 END as IsAutoIncrement,
case when (RF.RDB$IDENTITY_TYPE=1 OR V.RDB$UNIQUE_FLAG IS NULL) then 0 ELSE 1 END as IsUniqueKey,
RF.RDB$DESCRIPTION AS Description
FROM
RDB$RELATION_FIELDS RF
LEFT JOIN
RDB$FIELDS FLD ON RF.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME
LEFT JOIN
rdb$types FTY ON FTY.RDB$FIELD_NAME='RDB$FIELD_TYPE' AND FTY.RDB$TYPE=FLD.RDB$FIELD_TYPE
LEFT JOIN
(
SELECT RI.RDB$RELATION_NAME,RI.RDB$UNIQUE_FLAG,RS.RDB$FIELD_NAME,RC.RDB$CONSTRAINT_TYPE FROM RDB$INDICES RI
LEFT JOIN
RDB$RELATION_CONSTRAINTS RC ON RC.RDB$INDEX_NAME = RI.RDB$INDEX_NAME
LEFT JOIN
RDB$INDEX_SEGMENTS RS ON RS.RDB$FIELD_POSITION=0 AND RI.RDB$INDEX_NAME = RS.RDB$INDEX_NAME
) V ON RF.RDB$FIELD_NAME = V.RDB$FIELD_NAME AND RF.RDB$RELATION_NAME=V.RDB$RELATION_NAME
WHERE
RF.RDB$RELATION_NAME =@TableName
ORDER BY
RF.RDB$FIELD_POSITION";
}
internal static string GetDaMengColumns(string schemaName)
{
return string.Format(@"SELECT
a.table_name As tableName,
a.column_name As ColumnName,
a.data_length As MaxSize,
a.data_type As SqlType,
a.data_scale As Scale,
b.comments As Description,
e.data_default as DefaultValue,
case when (a.nullable = 'Y') then 1 else 0 end as IsNullable,
case when (d.constraint_type = 'P') then 1 else 0 end As IsPrimaryKey,
case when (d.constraint_type= 'U') then 1 else 0 end As IsUniqueKey,
case when f.info2 = 1 then 1 else 0 end as IsAutoIncrement
FROM all_tab_cols a
LEFT JOIN all_col_comments b ON b.table_name = a.table_name AND b.column_name = a.column_name AND a.owner = b.schema_name
LEFT JOIN all_tab_columns e ON a.table_name = e.table_name AND a.owner = e.owner and a.column_name = e.column_name
LEFT JOIN (SELECT f1.owner,f1.object_name As table_name,f0.name,f0.info2 FROM syscolumns f0
INNER JOIN dba_objects f1 ON f1.object_type = 'TABLE' AND info2 =1 AND f1.object_id = f0.id
) f ON f.name = a.column_name AND f.table_name = a.table_name AND f.owner = a.owner
LEFT JOIN (select ai.table_owner,ai.column_name,ai.table_name,ac.constraint_type
from all_ind_columns ai
right join (select table_owner,index_name from all_ind_columns group by table_owner,index_name having count(*)=1) v
on ai.table_owner=v.table_owner and ai.index_name=v.index_name
left join all_constraints ac on ac.owner=ai.table_owner and ac.index_name=ai.index_name
)d on d.TABLE_OWNER=a.OWNER and d.TABLE_NAME=a.TABLE_NAME and d.COLUMN_NAME=a.COLUMN_NAME
WHERE a.owner = UPPER('{0}') and a.TABLE_NAME=:TableName
ORDER BY a.column_id", schemaName);
}
internal static string GetKingBaseESColumns(string schemaName)
{
return String.Format(@"SELECT
a.column_name AS ColumnName,
CASE WHEN a.CHARACTER_MAXIMUM_LENGTH IS NOT NULL THEN a.CHARACTER_MAXIMUM_LENGTH ELSE a.NUMERIC_PRECISION END as MaxSize,
a.NUMERIC_SCALE as Scale,
case a.IS_NULLABLE when 'YES' then 1 else 0 end as IsNullable,
CASE d.typname WHEN 'int2' THEN 'smallint' WHEN 'int4' THEN 'integer' WHEN 'int8' THEN 'bigint' ELSE d.typname END AS SqlType,
CASE WHEN LEFT(a.column_default,8)='nextval(' THEN 1 ELSE 0 END AS IsAutoIncrement,
case c.CONSTRAINT_TYPE WHEN 'PRIMARY KEY' then 1 else 0 end as IsPrimaryKey,
case c.CONSTRAINT_TYPE when 'UNIQUE' then 1 else 0 end as IsUniqueKey,
case c.CONSTRAINT_TYPE when 'FOREIGN KEY' then 1 else 0 end as IsForeignKey,
a.COLUMN_DEFAULT AS DefaultValue,
d.description AS Description
FROM information_schema.columns a
LEFT JOIN information_schema.key_column_usage b
on b.TABLE_SCHEMA = a.TABLE_SCHEMA and b.TABLE_NAME = a.TABLE_NAME and b.COLUMN_NAME = a.COLUMN_NAME
LEFT JOIN information_schema.TABLE_CONSTRAINTS c on c.TABLE_SCHEMA = b.TABLE_SCHEMA and c.TABLE_NAME = b.TABLE_NAME and c.CONSTRAINT_NAME = b.CONSTRAINT_NAME
LEFT JOIN(SELECT s2.nspname, s1.relname, s3.attname, s4.description,s5.typname
FROM sys_class s1
LEFT JOIN sys_namespace s2 ON s2.oid = s1.relnamespace
LEFT JOIN sys_attribute s3 ON s3.attrelid = s1.oid
LEFT JOIN sys_description s4 ON s3.attrelid= s4.objoid AND s3.attnum = s4.objsubid
LEFT JOIN sys_type s5 ON s5.oid=s3.atttypid
) d ON d.nspname = a.table_schema AND d.relname = a.table_name AND d.attname = a.column_name
WHERE a.table_schema = '{0}' AND a.table_name = :TableName", schemaName);
}
#endregion
}
}