RHDWContext.cs 19 KB

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