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