using MJTop.Data.SPI;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Data.SQLite;
using System.Linq;
using System.Text.RegularExpressions;
namespace MJTop.Data.DatabaseInfo
{
public class SQLiteDBInfo : IDBInfo
{
private DB Db { get; set; }
///
/// 数据库工具
///
public Tool Tools
{
get;
private set;
}
public SQLiteDBInfo(DB db)
{
this.Db = db;
Refresh();
this.Tools = new Tool(db, this);
}
public string DBName
{
get { return System.IO.Path.GetFileNameWithoutExtension((Db.ConnectionStringBuilder as SQLiteConnectionStringBuilder).DataSource); }
}
public string Version
{
get;
private set;
}
// 3.31.1 => 3.31
public double VersionNumber
{
get
{
var mat = Regex.Match(Version, @"\D*(\d{1,}\.\d{1,})\D*", RegexOptions.Compiled);
double.TryParse(mat?.Groups[1]?.Value, out var res);
return res;
}
}
public NameValueCollection TableComments { get; private set; } = new NameValueCollection();
public List TableNames { get; private set; } = new List();
public IgCaseDictionary TableInfoDict { get; private set; }
public IgCaseDictionary> TableColumnNameDict { get; private set; }
public IgCaseDictionary> TableColumnInfoDict { get; private set; }
public IgCaseDictionary TableColumnComments { get; private set; }
private IgCaseDictionary DictColumnInfo { get; set; }
public NameValueCollection Views { get; private set; }
public NameValueCollection Procs { get; private set; }
public List DBNames { get { return DBName.TransList(); } }
public ColumnInfo this[string tableName, string columnName]
{
get
{
ColumnInfo colInfo;
var strKey = (tableName + "@" + columnName).ToLower();
DictColumnInfo.TryGetValue(strKey, out colInfo);
return colInfo;
}
}
public List this[string tableName]
{
get
{
List colNames;
TableColumnNameDict.TryGetValue(tableName, out colNames);
return colNames;
}
}
public bool Refresh()
{
this.DictColumnInfo = new IgCaseDictionary();
this.TableInfoDict = new IgCaseDictionary();
this.TableColumnNameDict = new IgCaseDictionary>();
this.TableColumnInfoDict = new IgCaseDictionary>();
this.TableColumnComments = new IgCaseDictionary();
string strSql = "SELECT name,'' as desc FROM sqlite_master WHERE type='table' order by name";
string viewSql = "SELECT name,sql FROM sqlite_master WHERE type='view' order by name asc";
string procSql = string.Empty; //Sqlite 没有存储过程功能!
try
{
this.TableComments = Db.GetDataTable(strSql).MapperNameValues("name", "desc");
this.Views = Db.ReadNameValues(viewSql);
this.Procs = new NameValueCollection();
if (this.TableComments != null && this.TableComments.Count > 0)
{
this.TableNames = TableComments.AllKeys.ToList();
var dbConn = Db.CreateConn();
dbConn.Open();
this.Version = dbConn.ServerVersion;
foreach (string tableName in TableNames)
{
TableInfo tabInfo = new TableInfo();
tabInfo.TableName = tableName;
tabInfo.TabComment = TableComments[tableName];
List lstColInfo = new List();
List lstColName = new List();
NameValueCollection nvcColDeText = new NameValueCollection();
DataRow[] columns = dbConn.GetSchema("COLUMNS").Select("TABLE_NAME='" + tableName + "'");
foreach (DataRow dr in columns)
{
ColumnInfo colInfo = new ColumnInfo();
colInfo.Colorder = dr["ORDINAL_POSITION"].ToString().ChangeType(0) + 1;
colInfo.ColumnName = dr["COLUMN_NAME"].ToString();
colInfo.Length = dr["CHARACTER_MAXIMUM_LENGTH"].ToString().ChangeType((int?)null);
//colInfo.Preci = dr["NUMERIC_PRECISION"].ToString().ChangeType(null);
colInfo.Scale = dr["NUMERIC_SCALE"].ToString().ChangeType((int?)null);
colInfo.IsPK = dr["PRIMARY_KEY"].ToString().ToLower() == "true" ? true : false;
colInfo.CanNull = dr["IS_NULLABLE"].ToString().ToLower() == "true" ? true : false;
colInfo.DefaultVal = dr["COLUMN_DEFAULT"].ToString();
colInfo.TypeName = dr["DATA_TYPE"].ToString();
if (colInfo.IsPK && string.Compare(colInfo.TypeName, "integer", true) == 0)
{
colInfo.IsIdentity = true;
}
if (colInfo.TypeName == "integer" || colInfo.TypeName == "bigint")
{
colInfo.Scale = null;
}
lstColInfo.Add(colInfo);
lstColName.Add(colInfo.ColumnName);
nvcColDeText.Add(colInfo.ColumnName, string.Empty);
var strKey = (tableName + "@" + colInfo.ColumnName).ToLower();
DictColumnInfo.Add(strKey, colInfo);
if (colInfo.IsPK)
{
tabInfo.PriKeyColName = colInfo.ColumnName;
if (colInfo.IsIdentity)
{
tabInfo.PriKeyType = PrimaryKeyType.AUTO;
}
else
{
tabInfo.PriKeyType = PrimaryKeyType.SET;
}
}
Global.Dict_Sqlite_DbType.TryGetValue(colInfo.TypeName, out DbType type);
colInfo.DbType = type;
}
tabInfo.Colnumns = lstColInfo;
this.TableInfoDict.Add(tableName, tabInfo);
this.TableColumnNameDict.Add(tableName, lstColName);
this.TableColumnInfoDict.Add(tableName, lstColInfo);
this.TableColumnComments.Add(tableName, nvcColDeText);
}
dbConn.Close();
}
}
catch (Exception ex)
{
LogUtils.LogError("DB", Developer.SysDefault, ex);
return false;
}
return this.TableComments.Count == this.TableInfoDict.Count;
}
#region Sqlite获取列信息
//private List SqliteColInfo(string tableName)
//{
// List lstCols = new List();
// var dbConn = Db.CreateConn();
// dbConn.Open();
// DataRow[] columns = dbConn.GetSchema("COLUMNS").Select("TABLE_NAME='" + tableName + "'");
// foreach (DataRow dr in columns)
// {
// ColumnInfo colInfo = new ColumnInfo();
// colInfo.Colorder = dr["ORDINAL_POSITION"].ToString().ChangeType(0);
// colInfo.ColumnName = dr["COLUMN_NAME"].ToString();
// colInfo.Length = dr["CHARACTER_MAXIMUM_LENGTH"].ToString().ChangeType((int?)null);
// //colInfo.Preci = dr["NUMERIC_PRECISION"].ToString().ChangeType(null);
// colInfo.Scale = dr["NUMERIC_SCALE"].ToString().ChangeType((int?)null);
// colInfo.IsPK = dr["PRIMARY_KEY"].ToString().ToLower() == "true" ? true : false;
// colInfo.CanNull = dr["IS_NULLABLE"].ToString().ToLower() == "true" ? true : false;
// colInfo.DefaultVal = dr["COLUMN_DEFAULT"].ToString();
// colInfo.TypeName = dr["DATA_TYPE"].ToString();
// if (colInfo.IsPK && string.Compare(colInfo.TypeName, "integer", true) == 0)
// {
// colInfo.IsIdentity = true;
// }
// lstCols.Add(colInfo);
// }
// dbConn.Close();
// return lstCols;
//}
#endregion
public Dictionary GetTableStruct_Modify()
{
throw new Exception("SQLite不支持 记录表结构更改时间!");
}
public bool IsExistTable(string tableName)
{
return TableNames.Contains(tableName, StringComparer.OrdinalIgnoreCase);
}
public bool IsExistColumn(string tableName, string columnName)
{
var strKey = (tableName + "@" + columnName);
return DictColumnInfo.ContainsKey(strKey);
}
public string GetColumnComment(string tableName, string columnName)
{
throw new Exception("Sqlite不支持表列描述!");
}
public string GetTableComment(string tableName)
{
throw new Exception("Sqlite不支持表列描述!");
}
public List GetColumns(string tableName)
{
List colInfos = null;
TableColumnInfoDict.TryGetValue(tableName, out colInfos);
return colInfos;
}
public bool SetTableComment(string tableName, string comment)
{
throw new Exception("Sqlite不支持表列描述!");
}
public bool SetColumnComment(string tableName, string columnName, string comment)
{
throw new Exception("Sqlite不支持表列描述!");
}
public bool DropTable(string tableName)
{
Db.CheckTabStuct(tableName);
string drop_sql = string.Empty;
try
{
drop_sql = "drop table " + tableName;
Db.ExecSql(drop_sql);
this.TableComments.Remove(tableName);
this.TableNames = TableComments.AllKeys.ToList();
this.TableInfoDict.Remove(tableName);
this.TableColumnInfoDict.Remove(tableName);
this.TableColumnComments.Remove(tableName);
var lstColName = TableColumnNameDict[tableName];
foreach (var colName in lstColName)
{
var strKey = (tableName + "@" + colName).ToLower();
this.DictColumnInfo.Remove(strKey);
}
this.TableColumnNameDict.Remove(tableName);
}
catch (Exception ex)
{
LogUtils.LogError("DB", Developer.SysDefault, ex, drop_sql);
return false;
}
return true;
}
public bool DropColumn(string tableName, string columnName)
{
Db.CheckTabStuct(tableName, columnName);
if (Db.Single(string.Format("select count(1) from {0}", tableName), 0) > 0)
{
throw new Exception("Sqlite不支持对已有数据的表的结构进行更改!");
}
var strKey = (tableName + "@" + columnName);
string ctor_sql = string.Empty;
string drop_sql = string.Empty;
string rename_sql = string.Empty;
try
{
//Sqlite 不支持直接删除列 的 处理方式,这里先创查询建 对应表的结构(排除要删除的列),然后删除原来的表,最后重命名新表的 表名称。
//该方法适用于 表中 没有数据的 情况。
{
var lstColName = this[tableName].Where(t => !t.Equals(columnName, StringComparison.OrdinalIgnoreCase));
string temp_Name = tableName + DateTime.Now.ToString("yyyMMddhhmmssfff");
ctor_sql = "create table {0} as select {1} from {2}";
ctor_sql = string.Format(ctor_sql, temp_Name, string.Join(",", lstColName), tableName);
drop_sql = string.Format("drop table if exists {0}", tableName);
rename_sql = string.Format("alter table {0} rename to {1}", temp_Name, tableName);
Db.ExecSqlTran(ctor_sql, drop_sql, rename_sql);
this.DictColumnInfo.Remove(strKey);
var nvc = TableColumnComments[tableName];
nvc.Remove(columnName);
TableColumnNameDict[tableName] = nvc.AllKeys.ToList();
var lstColInfo = TableColumnInfoDict[tableName];
ColumnInfo curColInfo = null;
lstColInfo.ForEach(t =>
{
if (t.ColumnName.Equals(columnName, StringComparison.OrdinalIgnoreCase))
{
curColInfo = t;
//tabInfo 对应的 主键类型和主键列 也需要 跟着修改。
if (curColInfo.IsPK)
{
var tabInfo = TableInfoDict[tableName];
tabInfo.PriKeyType = PrimaryKeyType.UNKNOWN;
tabInfo.PriKeyColName = null;
TableInfoDict[tableName] = tabInfo;
}
return;
}
});
lstColInfo.Remove(curColInfo);
TableColumnInfoDict[tableName] = lstColInfo;
}
}
catch (Exception ex)
{
LogUtils.LogError("DB", Developer.SysDefault, ex, ctor_sql, drop_sql, rename_sql);
return false;
}
return true;
}
}
}