using System; using System.Collections.Generic; using System.Data.SQLite; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SQLite { public abstract class SQLiteDbContext { public List<IDBTable> DbSet = new List<IDBTable>(); public SQLiteHelper sqliteHelper { get; private set; } string ConnectionString { get { return string.Format("Data Source={0};Version=3;", DBPath); } } public string DBPath { get; private set; } = @"test.sqlite3"; public SQLiteDbContext(string dbPath) { DBPath = dbPath; Constructor(); } void Constructor() { sqliteHelper = new SQLiteHelper(); sqliteHelper.ConnectionString = ConnectionString; var type = GetType(); foreach (var p in type.GetProperties()) { if (typeof(IDBTable).IsAssignableFrom(p.PropertyType)) { DbSet.Add(p.GetValue(this) as IDBTable); } } foreach (IDBTable dBTable in DbSet) { dBTable.Init(sqliteHelper); } } public void SetDBPath(string dbPath) { DBPath = dbPath; sqliteHelper.ConnectionString = ConnectionString; } void Build() { string directoryname = System.IO.Path.GetDirectoryName(DBPath); if (!string.IsNullOrEmpty(directoryname) && !System.IO.Directory.Exists(directoryname)) System.IO.Directory.CreateDirectory(directoryname); SQLiteConnection.CreateFile(DBPath); foreach (IDBTable dBTable in DbSet) dBTable.Create(); } void Rebuild() { if (!System.IO.File.Exists(DBPath)) { Build(); } else { //把文件删除,重建 System.IO.File.Delete(DBPath); Build(); } } void Load() { foreach(var table in DbSet) { table.MaxID = LoadID(table.TableName); } } long LoadID(string tablename) { string cmd = $"SELECT MAX(ID) FROM {tablename}"; var reponse = sqliteHelper.ExecuteScalar(cmd); if (reponse is DBNull) return -1; else return System.Convert.ToInt64(reponse); } /// <summary> /// 给定分区数 检测表是否存在,合法 /// </summary> /// <param name="nbolts"></param> /// <returns>false 表不合法,重建; true 正常!</returns> public bool Init() { if (!System.IO.File.Exists(DBPath)) { Build(); return false; } //TODO, 表不对删除就好。。。没必要重新创建数据库 //任意一个表不对,或者不存在,都必须重建 Dictionary<string, string> ddls = new Dictionary<string, string>(); foreach (IDBTable tb in DbSet) { ddls.Add(tb.TableName, tb.DDL); } bool isVaild = sqliteHelper.IsTableValid(ddls, out Dictionary<string, SQLiteHelper.IsTableValidResult> results); if (!isVaild)//不合法 { if (results.Any(kv => kv.Value == SQLiteHelper.IsTableValidResult.FormatErr)) { //先备份 //File.Copy(DBPath, DBPath + $".{DateTime.Now:yyyyMMddHHmmss}.bk"); //重建数据库 File.Move(DBPath, DBPath + $".{DateTime.Now:yyyyMMddHHmmss}.bk"); Build(); return false; } //有表 不对 foreach (var kv in results) { switch (kv.Value) { case SQLiteHelper.IsTableValidResult.NotHere: { //直接创建表 sqliteHelper.ExecuteNonQuery(ddls[kv.Key]); } break; //case SQLiteHelper.IsTableValidResult.FormatErr: // { // //先删除表,再创建 // sqliteHelper.ExecuteNonQuery($"DROP TABLE {kv.Key}"); // sqliteHelper.ExecuteNonQuery(ddls[kv.Key]); // } // break; } } } //检查INDEX Dictionary<string, string> indexs = new Dictionary<string, string>(); foreach (IDBTable tb in DbSet) { if(!string.IsNullOrEmpty(tb.INDEX)) indexs.Add(tb.TableName, tb.INDEX); } if (indexs.Count() > 0) { isVaild = sqliteHelper.IsIndexValid(indexs, out results); if (!isVaild)//不合法 { foreach (var kv in results) { switch (kv.Value) { case SQLiteHelper.IsTableValidResult.NotHere: { //直接创建表 sqliteHelper.ExecuteNonQuery(indexs[kv.Key]); } break; case SQLiteHelper.IsTableValidResult.FormatErr: { //先删除INDEX,再创建 sqliteHelper.ExecuteNonQuery($"DROP INDEX {kv.Key}_INDEX"); sqliteHelper.ExecuteNonQuery(indexs[kv.Key]); } break; } } } } //最后也要加载数据 Load(); return isVaild; } /// <summary> /// 当出错,不重建表 /// </summary> /// <returns></returns> public bool InitNoBuild() { if (!System.IO.File.Exists(DBPath)) { Build(); return false; } //TODO, 表不对删除就好。。。没必要重新创建数据库 //任意一个表不对,或者不存在,都必须重建 Dictionary<string, string> ddls = new Dictionary<string, string>(); foreach (IDBTable tb in DbSet) { ddls.Add(tb.TableName, tb.DDL); } if (sqliteHelper.IsTableValid(ddls)) { Load(); return true; } else { return false; } } public void KeepDBSize(int month) { if (month < 1) month = 1; //最少保存上个月与这个月的数据 DateTime del_time = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1); del_time = del_time.AddMonths(-month); List<string> sqls = new List<string>(); //正常应该为 //DELETE FROM ScanData WHERE Time < '2020-06-08' // //但 有INDEX 后 下面会更快 //DELETE FROM ScanData WHERE ID <= (SELECT ID FROM ScanData WHERE Time < '2020-06-08' ORDER BY ID DESC LIMIT 1); //枚举全部TbXXX, 带有TimeAttribute 都删除 foreach (IDBTable tb in DbSet) { sqls.Add(tb.GetDeleteSQL(del_time)); } //把sqls里面为空的全部删除 sqls.RemoveAll(sql => sql == null); if (sqls.Count == 0) return; sqliteHelper.QueryTran(sqls); } } }