RHDWContext.cs 19 KB

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