RHDWContext.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. using SQLite.CodeFirst;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel.DataAnnotations.Schema;
  5. using System.Configuration;
  6. using System.Data.Common;
  7. using System.Data.Entity;
  8. using System.Data.Entity.Core.Common;
  9. using System.Data.Entity.Core.Common.CommandTrees;
  10. using System.Data.Entity.Core.Metadata.Edm;
  11. using System.Data.Entity.Infrastructure;
  12. using System.Data.Entity.Infrastructure.Interception;
  13. using System.Data.Entity.ModelConfiguration.Conventions;
  14. using System.Data.Entity.Validation;
  15. using System.Data.SQLite;
  16. using System.Data.SQLite.EF6;
  17. using System.IO;
  18. using System.Linq;
  19. using System.Linq.Expressions;
  20. using System.Reflection;
  21. using System.Text;
  22. using System.Text.RegularExpressions;
  23. using System.Threading.Tasks;
  24. using System.Windows;
  25. using XdCxRhDW.Entity;
  26. namespace XdCxRhDW.Repostory
  27. {
  28. class DbTableColumnInfo
  29. {
  30. public string name { get; set; }
  31. public string type { get; set; }
  32. public int notnull { get; set; }
  33. public int pk { get; set; }
  34. }
  35. public class DbContextBase : DbContext
  36. {
  37. public DbContextBase(string nameOrConnectionString)
  38. : base(nameOrConnectionString)
  39. {
  40. }
  41. public DbContextBase(DbConnection con, bool contextOwnsConnection)
  42. : base(con, contextOwnsConnection)
  43. {
  44. }
  45. /// <summary>
  46. /// 同步数据库表、字段、索引
  47. /// </summary>
  48. public void SyncDb()
  49. {
  50. SyncTable();
  51. SyncTableField();
  52. SyncIndex();
  53. }
  54. /// <summary>
  55. /// 手动创建组合索引(如果不存在)
  56. /// </summary>
  57. public void CreateCombinedIndex<TEntityType>(Expression<Func<TEntityType, object>> expr)
  58. {
  59. var props = ((NewExpression)expr.Body).Members.Select(p => p.Name).OrderBy(p => p).ToList();
  60. if (props.Count < 1) return;
  61. var name = string.Join("_", props);
  62. var tableName = typeof(TEntityType).GetCustomAttribute<TableAttribute>()?.Name;
  63. if (string.IsNullOrWhiteSpace(tableName))
  64. tableName = typeof(TEntityType).Name;
  65. string indexName = $"IX_{tableName}_{name}";
  66. StringBuilder sb = new StringBuilder();
  67. int idx = 0;
  68. foreach (var item in props)
  69. {
  70. if (idx < props.Count - 1)
  71. sb.Append($"'{item}',");
  72. else
  73. sb.Append($"'{item}'");
  74. idx++;
  75. }
  76. var columnStr = sb.ToString();
  77. var index = this.Database.SqlQuery<string>($"SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='{tableName}' and name='{indexName}'").FirstOrDefault();
  78. if (index == null)
  79. this.Database.ExecuteSqlCommand($"CREATE INDEX '{indexName}' ON {tableName} ({columnStr})");
  80. }
  81. /// <summary>
  82. /// 手动创建组合索引(如果不存在)
  83. /// </summary>
  84. public void CreateCombinedIndex(string tableName, string[] propNames)
  85. {
  86. if (string.IsNullOrWhiteSpace(tableName)) return;
  87. if (propNames == null || propNames.Length == 0) return;
  88. var props = propNames.OrderBy(p => p).ToList();
  89. var name = string.Join("_", props);
  90. string indexName = $"IX_{tableName}_{name}";
  91. StringBuilder sb = new StringBuilder();
  92. int idx = 0;
  93. foreach (var item in props)
  94. {
  95. if (idx < props.Count - 1)
  96. sb.Append($"'{item}',");
  97. else
  98. sb.Append($"'{item}'");
  99. idx++;
  100. }
  101. var columnStr = sb.ToString();
  102. var index = this.Database.SqlQuery<string>($"SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='{tableName}' and name='{indexName}'").FirstOrDefault();
  103. if (index == null)
  104. this.Database.ExecuteSqlCommand($"CREATE INDEX '{indexName}' ON {tableName} ({columnStr})");
  105. }
  106. void SyncIndex()
  107. {
  108. var tables = this.Database.SqlQuery<string>("select name from sqlite_master where type='table' and name not like 'sqlite%'").ToList();
  109. var props = this.GetType().GetProperties();
  110. List<Type> entityTypes = new List<Type>();
  111. foreach (var prop in props)
  112. {
  113. bool isDbSet = prop.PropertyType.IsGenericType && typeof(DbSet<>) == prop.PropertyType.GetGenericTypeDefinition();
  114. if (isDbSet)
  115. {
  116. var entityType = prop.PropertyType.GenericTypeArguments[0];
  117. entityTypes.Add(entityType);
  118. }
  119. }
  120. foreach (var table in tables)
  121. {
  122. var res = this.Database.SqlQuery<DbTableColumnInfo>($"PRAGMA table_info([{table}])").ToList();
  123. var entityType = entityTypes.FirstOrDefault(p => p.Name == table);
  124. if (entityType == null) continue;
  125. //创建具有Index特性的索引列
  126. var entityProps = entityType.GetProperties().Where(p =>
  127. p.CanRead
  128. && p.Name.ToUpper() != "ID"
  129. && p.CanWrite
  130. && !p.GetMethod.IsVirtual
  131. && p.GetCustomAttribute<IndexAttribute>() != null
  132. && p.GetCustomAttribute<NotMappedAttribute>() == null);
  133. foreach (var prop in entityProps)
  134. {
  135. var index = this.Database.SqlQuery<string>($"SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='{table}' and name='IX_{table}_{prop.Name}'").FirstOrDefault();
  136. if (index == null)
  137. {
  138. this.Database.ExecuteSqlCommand($"CREATE INDEX 'IX_{table}_{prop.Name}' ON {table} ('{prop.Name}')");
  139. }
  140. }
  141. //创建类上具有IndexCombined特性的组合索引
  142. var attrs = entityType.GetCustomAttributes<IndexCombinedAttribute>();
  143. foreach (var item in attrs)
  144. {
  145. CreateCombinedIndex(table, item.Names);
  146. }
  147. }
  148. }
  149. void SyncTable()
  150. {
  151. var tables = this.Database.SqlQuery<string>("select name from sqlite_master where type='table' and name not like 'sqlite%'").ToList();
  152. var props = this.GetType().GetProperties();
  153. Dictionary<string, Type> list = new Dictionary<string, Type>();
  154. foreach (var prop in props)
  155. {
  156. bool isDbSet = prop.PropertyType.IsGenericType && typeof(DbSet<>) == prop.PropertyType.GetGenericTypeDefinition();
  157. if (isDbSet)
  158. {
  159. var entityType = prop.PropertyType.GenericTypeArguments[0];
  160. var name = entityType.GetCustomAttribute<TableAttribute>()?.Name;
  161. if (name == null)
  162. {
  163. name = entityType.Name;
  164. }
  165. list.Add(name, entityType);
  166. }
  167. }
  168. foreach (var item in list)
  169. {
  170. if (!tables.Contains(item.Key))
  171. {
  172. var entityProps = item.Value.GetProperties().Where(p =>
  173. p.CanRead
  174. && p.CanWrite
  175. && !p.GetMethod.IsVirtual
  176. && p.GetCustomAttribute<NotMappedAttribute>() == null);
  177. item.Value.GetProperties().Where(p => p.CanWrite);
  178. StringBuilder sb = new StringBuilder();
  179. sb.Append($"create table {item.Key}(ID integer primary key autoincrement");
  180. foreach (var prop in entityProps)
  181. {
  182. if (prop.Name.ToLower() == "id") continue;
  183. bool isNullable = prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>);
  184. string typeStr = "";
  185. var type = prop.PropertyType;
  186. if (prop.PropertyType.IsGenericType)
  187. {
  188. type = prop.PropertyType.GenericTypeArguments[0];
  189. }
  190. if (type == typeof(string))
  191. {
  192. typeStr = "nvarchar";
  193. }
  194. else if (type == typeof(int) || type == typeof(long) || prop.PropertyType.IsEnum)
  195. {
  196. typeStr = "int";
  197. }
  198. else if (type == typeof(double) || type == typeof(float))
  199. {
  200. typeStr = "float";
  201. }
  202. else if (type == typeof(DateTime))
  203. {
  204. typeStr = "datetime";
  205. }
  206. sb.Append($",{prop.Name} {typeStr}");
  207. if (!isNullable)
  208. {
  209. sb.Append(" not null");
  210. }
  211. }
  212. sb.Append(")");
  213. string createTableSql = sb.ToString();
  214. Database.ExecuteSqlCommand(createTableSql);
  215. }
  216. }
  217. }
  218. void SyncTableField()
  219. {
  220. var tables = this.Database.SqlQuery<string>("select name from sqlite_master where type='table' and name not like 'sqlite%'").ToList();
  221. var props = this.GetType().GetProperties();
  222. List<Type> entityTypes = new List<Type>();
  223. foreach (var prop in props)
  224. {
  225. bool isDbSet = prop.PropertyType.IsGenericType && typeof(DbSet<>) == prop.PropertyType.GetGenericTypeDefinition();
  226. if (isDbSet)
  227. {
  228. var entityType = prop.PropertyType.GenericTypeArguments[0];
  229. entityTypes.Add(entityType);
  230. }
  231. }
  232. foreach (var table in tables)
  233. {
  234. var res = this.Database.SqlQuery<DbTableColumnInfo>($"PRAGMA table_info([{table}])").ToList();
  235. var entityType = entityTypes.FirstOrDefault(p => p.Name == table);
  236. if (entityType == null) continue;
  237. var entityProps = entityType.GetProperties().Where(p =>
  238. p.CanRead
  239. && p.CanWrite
  240. && !p.GetMethod.IsVirtual
  241. && p.GetCustomAttribute<NotMappedAttribute>() == null);
  242. foreach (var prop in entityProps)
  243. {
  244. var find = res.Find(p => p.name.ToLower() == prop.Name.ToLower());
  245. if (find == null)
  246. {
  247. string typeStr = "";
  248. var type = prop.PropertyType;
  249. if (prop.PropertyType.IsGenericType)
  250. {
  251. type = prop.PropertyType.GenericTypeArguments[0];
  252. }
  253. if (type == typeof(string))
  254. {
  255. typeStr = "nvarchar";
  256. }
  257. else if (type == typeof(int) || type == typeof(long) || prop.PropertyType.IsEnum)
  258. {
  259. typeStr = "int";
  260. }
  261. else if (type == typeof(double) || type == typeof(float))
  262. {
  263. typeStr = "float";
  264. }
  265. else if (type == typeof(DateTime))
  266. {
  267. typeStr = "datetime";
  268. }
  269. else if (type == typeof(bool))
  270. {
  271. typeStr = "int";
  272. }
  273. bool isNullable = prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>);
  274. string updateTableSql;
  275. if (isNullable)
  276. updateTableSql = $"alter table {table} add column {prop.Name} {typeStr}";
  277. else
  278. {
  279. if (typeStr == "int" || typeStr == "float")
  280. updateTableSql = $"alter table {table} add column {prop.Name} {typeStr} not null default 0";
  281. else if (typeStr == "nvarchar")
  282. updateTableSql = $"alter table {table} add column {prop.Name} {typeStr} not null default ''";
  283. else if (typeStr == "datetime")
  284. updateTableSql = $"alter table {table} add column {prop.Name} {typeStr} not null default '{DateTime.Now:yyyy-MM-dd HH:mm:ss}'";
  285. else
  286. updateTableSql = $"alter table {table} add column {prop.Name} {typeStr}";
  287. }
  288. this.Database.ExecuteSqlCommand(updateTableSql);
  289. }
  290. }
  291. }
  292. }
  293. }
  294. public class RHDWLogContext : DbContextBase
  295. {
  296. public string DbFile;
  297. public RHDWLogContext() : base("LogDbCon") //配置使用的连接名
  298. {
  299. //|DataDirectory|在mvc等程序中代表了App_Data,在普通程序中代表程序根目录
  300. var dbFile = Database.Connection.ConnectionString.Replace("Data Source=", "").Replace("|DataDirectory|\\", "");
  301. this.DbFile = dbFile;
  302. }
  303. protected override void OnModelCreating(DbModelBuilder modelBuilder)
  304. {
  305. this.Database.Log = msg =>
  306. {
  307. };
  308. modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
  309. modelBuilder.Configurations.AddFromAssembly(typeof(RHDWLogContext).Assembly);//自动加载Entity-Type
  310. var sqliteConnectionInitializer = new SqliteCreateDatabaseIfNotExists<RHDWLogContext>(modelBuilder);
  311. Database.SetInitializer(sqliteConnectionInitializer);
  312. base.OnModelCreating(modelBuilder);
  313. }
  314. public DbSet<LogRes> LogRes { set; get; }
  315. }
  316. /// <summary>
  317. /// 基础表上下文(id为int)
  318. /// </summary>
  319. public class RHDWContext : DbContextBase
  320. {
  321. public string DbFile;
  322. public static RHDWContext GetContext(bool readOnly = false)
  323. {
  324. string conStr = ConfigurationManager.ConnectionStrings["DbCon"].ConnectionString.Trim();
  325. if (conStr.EndsWith(";"))
  326. conStr = conStr.Substring(0, conStr.Length - 1);
  327. conStr = $"{conStr};Version=3";//Journal Mode=Off
  328. if (readOnly)
  329. {
  330. conStr = $"{conStr};Read Only=True";
  331. }
  332. SQLiteConnection con = new SQLiteConnection(conStr);
  333. if (!readOnly)
  334. {
  335. //con.Open();
  336. //var cmd = con.CreateCommand();
  337. //cmd.CommandText = "PRAGMA journal_mode=WAL";
  338. //cmd.ExecuteNonQuery();
  339. //con.Close();
  340. }
  341. var res = new RHDWContext(con);
  342. return res;
  343. }
  344. private RHDWContext(DbConnection con)
  345. : base(con, true)
  346. {
  347. var dbFile = Database.Connection.ConnectionString.Replace("Data Source=", "").Replace("|DataDirectory|\\", "");
  348. this.DbFile = dbFile;
  349. }
  350. //public RHDWContext() : base("DbCon") //配置使用的连接名
  351. //{
  352. // //|DataDirectory|在mvc等程序中代表了App_Data,在普通程序中代表程序根目录
  353. // this.DbFile = Database.Connection.ConnectionString.Replace("Data Source=", "").Replace("|DataDirectory|\\", "");
  354. //}
  355. public Task<List<T>> SqlQueryAsync<T>(string sql)
  356. {
  357. return this.Database.SqlQuery<T>(sql).ToListAsync();
  358. }
  359. public Task<T> SqlQueryOneAsync<T>(string sql)
  360. {
  361. return this.Database.SqlQuery<T>(sql).FirstOrDefaultAsync();
  362. }
  363. protected override void OnModelCreating(DbModelBuilder modelBuilder)
  364. {
  365. this.Database.Log = msg =>
  366. {
  367. };
  368. modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
  369. modelBuilder.Configurations.AddFromAssembly(typeof(RHDWContext).Assembly);//自动加载Entity-Type
  370. var sqliteConnectionInitializer = new SqliteCreateDatabaseIfNotExists<RHDWContext>(modelBuilder);
  371. Database.SetInitializer(sqliteConnectionInitializer);
  372. base.OnModelCreating(modelBuilder);
  373. }
  374. public DbSet<XlInfo> XlInfos { set; get; }
  375. public DbSet<TaskInfo> TaskInfos { set; get; }
  376. public DbSet<TaskSig> TaskSigs { set; get; }
  377. public DbSet<TxInfo> TxInfos { get; set; }
  378. public DbSet<SatInfo> SatInfos { get; set; }
  379. public DbSet<FixedStation> FixedStation { get; set; }
  380. public DbSet<SigInfo> SigInfos { get; set; }
  381. public DbSet<SigDelay> SigDelays { get; set; }
  382. public DbSet<TargetInfo> TargetInfos { get; set; }
  383. public DbSet<SysSetings> SysSetings { get; set; }
  384. public DbSet<TaskRunnningInfo> TaskRunnningInfos { get; set; }
  385. }
  386. /// <summary>
  387. /// 分区表上下文(id为long)
  388. /// </summary>
  389. public class RHDWPartContext : DbContextBase
  390. {
  391. private string DbFile;
  392. public static RHDWPartContext GetContext(string dbFile, bool createDb = false, bool readOnly = false)
  393. {
  394. if (!File.Exists(dbFile) && !createDb)
  395. {
  396. return null;
  397. }
  398. string connectionString;
  399. if (readOnly)
  400. {
  401. connectionString = $@"Data Source={dbFile};RAGMA mode=ReadOnly;Journal=WAL";
  402. }
  403. else
  404. {
  405. connectionString = $@"Data Source={dbFile};Journal=WAL";
  406. }
  407. SQLiteConnection con = new SQLiteConnection(connectionString);
  408. return new RHDWPartContext(con);
  409. }
  410. public static RHDWPartContext GetContext(DateTime partTime, bool createDb = false, bool readOnly = false)
  411. {
  412. var dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DbPart");
  413. var dayFile = Path.Combine(dir, $@"{partTime.Year}\{partTime:MMdd}.db");
  414. if (!File.Exists(dayFile) && !createDb)
  415. {
  416. return null;
  417. }
  418. string connectionString;
  419. if (readOnly)
  420. {
  421. connectionString = $@"Data Source=|DataDirectory|\DbPart\{partTime.Year}\{partTime:MMdd}.db;PRAGMA mode=ReadOnly;Journal=WAL";
  422. }
  423. else
  424. {
  425. connectionString = $@"Data Source=|DataDirectory|\DbPart\{partTime.Year}\{partTime:MMdd}.db;Journal=WAL";
  426. }
  427. SQLiteConnection con = new SQLiteConnection(connectionString);
  428. return new RHDWPartContext(con);
  429. }
  430. private RHDWPartContext(DbConnection con)
  431. : base(con, true)
  432. {
  433. var dbFile = Database.Connection.ConnectionString.Replace("Data Source=", "").Replace("|DataDirectory|\\", "");
  434. this.DbFile = dbFile;
  435. }
  436. protected override void OnModelCreating(DbModelBuilder modelBuilder)
  437. {
  438. this.Database.Log = msg =>
  439. {
  440. };
  441. modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
  442. modelBuilder.Configurations.AddFromAssembly(typeof(RHDWPartContext).Assembly);
  443. var sqliteConnectionInitializer = new SqliteCreateDatabaseIfNotExists<RHDWPartContext>(modelBuilder);
  444. Database.SetInitializer(sqliteConnectionInitializer);
  445. base.OnModelCreating(modelBuilder);
  446. }
  447. public DbSet<StationRes> StationRes { get; set; }
  448. public DbSet<CxRes> CxRes { get; set; }
  449. public DbSet<CgRes> CgRes { get; set; }
  450. public DbSet<CgXgfRes> CgXgfRes { get; set; }
  451. public DbSet<PosRes> PosRes { get; set; }
  452. public DbSet<CheckRes> CheckRes { get; set; }
  453. }
  454. public class SqliteConfiguration : DbConfiguration
  455. {
  456. public SqliteConfiguration()
  457. {
  458. DbInterception.Add(new SqliteInterceptor());//拦截器
  459. SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);
  460. SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
  461. SetProviderServices("System.Data.SQLite", (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
  462. }
  463. }
  464. }