ZhiYeJianKang_PeiXun/cyqdata-master/SQL/Schema/TableSchema.cs
2025-02-20 15:41:53 +08:00

1231 lines
61 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
}