MySqlSync.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel.DataAnnotations.Schema;
  4. using System.Data.Entity;
  5. using System.Linq;
  6. using System.Linq.Expressions;
  7. using System.Reflection;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. namespace XdCxRhDW.Repostory
  11. {
  12. public class MySqlSync:MySqlContext
  13. {
  14. /// <summary>
  15. /// 同步数据库表、字段、索引
  16. /// </summary>
  17. public void SyncDb()
  18. {
  19. SyncTable();
  20. SyncTableField();
  21. SyncIndex();
  22. }
  23. void SyncTable()
  24. {
  25. var tables = this.Database.SqlQuery<string>("select * from information_schema.tables").ToList();
  26. var props = this.GetType().GetProperties();
  27. Dictionary<string, Type> list = new Dictionary<string, Type>();
  28. foreach (var prop in props)
  29. {
  30. bool isDbSet = prop.PropertyType.IsGenericType && typeof(DbSet<>) == prop.PropertyType.GetGenericTypeDefinition();
  31. if (isDbSet)
  32. {
  33. var entityType = prop.PropertyType.GenericTypeArguments[0];
  34. var name = entityType.GetCustomAttribute<TableAttribute>()?.Name;
  35. if (name == null)
  36. {
  37. name = entityType.Name;
  38. }
  39. list.Add(name, entityType);
  40. }
  41. }
  42. foreach (var item in list)
  43. {
  44. if (!tables.Contains(item.Key))
  45. {
  46. var entityProps = item.Value.GetProperties().Where(p =>
  47. p.CanRead
  48. && p.CanWrite
  49. && !p.GetMethod.IsVirtual
  50. && p.GetCustomAttribute<NotMappedAttribute>() == null);
  51. item.Value.GetProperties().Where(p => p.CanWrite);
  52. StringBuilder sb = new StringBuilder();
  53. sb.Append($"create table {item.Key}(ID integer primary key autoincrement");
  54. foreach (var prop in entityProps)
  55. {
  56. if (prop.Name.ToLower() == "id") continue;
  57. bool isNullable = prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>);
  58. string typeStr = "";
  59. var type = prop.PropertyType;
  60. if (prop.PropertyType.IsGenericType)
  61. {
  62. type = prop.PropertyType.GenericTypeArguments[0];
  63. }
  64. if (type == typeof(string))
  65. {
  66. typeStr = "nvarchar";
  67. }
  68. else if (type == typeof(int) || type == typeof(long) || prop.PropertyType.IsEnum)
  69. {
  70. typeStr = "int";
  71. }
  72. else if (type == typeof(double) || type == typeof(float))
  73. {
  74. typeStr = "float";
  75. }
  76. else if (type == typeof(DateTime))
  77. {
  78. typeStr = "datetime";
  79. }
  80. sb.Append($",{prop.Name} {typeStr}");
  81. if (!isNullable)
  82. {
  83. sb.Append(" not null");
  84. }
  85. }
  86. sb.Append(")");
  87. string createTableSql = sb.ToString();
  88. Database.ExecuteSqlCommand(createTableSql);
  89. }
  90. }
  91. }
  92. void SyncIndex()
  93. {
  94. var tables = this.Database.SqlQuery<string>("select name from sqlite_master where type='table' and name not like 'sqlite%'").ToList();
  95. var props = this.GetType().GetProperties();
  96. List<Type> entityTypes = new List<Type>();
  97. foreach (var prop in props)
  98. {
  99. bool isDbSet = prop.PropertyType.IsGenericType && typeof(DbSet<>) == prop.PropertyType.GetGenericTypeDefinition();
  100. if (isDbSet)
  101. {
  102. var entityType = prop.PropertyType.GenericTypeArguments[0];
  103. entityTypes.Add(entityType);
  104. }
  105. }
  106. foreach (var table in tables)
  107. {
  108. var res = this.Database.SqlQuery<DbTableColumnInfo>($"PRAGMA table_info([{table}])").ToList();
  109. var entityType = entityTypes.FirstOrDefault(p => p.Name == table);
  110. if (entityType == null) continue;
  111. //创建具有Index特性的索引列
  112. var entityProps = entityType.GetProperties().Where(p =>
  113. p.CanRead
  114. && p.Name.ToUpper() != "ID"
  115. && p.CanWrite
  116. && !p.GetMethod.IsVirtual
  117. && p.GetCustomAttribute<IndexAttribute>() != null
  118. && p.GetCustomAttribute<NotMappedAttribute>() == null);
  119. foreach (var prop in entityProps)
  120. {
  121. 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();
  122. if (index == null)
  123. {
  124. this.Database.ExecuteSqlCommand($"CREATE INDEX 'IX_{table}_{prop.Name}' ON {table} ('{prop.Name}')");
  125. }
  126. }
  127. //创建类上具有IndexCombined特性的组合索引
  128. var attrs = entityType.GetCustomAttributes<IndexCombinedAttribute>();
  129. foreach (var item in attrs)
  130. {
  131. CreateCombinedIndex(table, item.Names);
  132. }
  133. }
  134. }
  135. void SyncTableField()
  136. {
  137. var tables = this.Database.SqlQuery<string>("select name from sqlite_master where type='table' and name not like 'sqlite%'").ToList();
  138. var props = this.GetType().GetProperties();
  139. List<Type> entityTypes = new List<Type>();
  140. foreach (var prop in props)
  141. {
  142. bool isDbSet = prop.PropertyType.IsGenericType && typeof(DbSet<>) == prop.PropertyType.GetGenericTypeDefinition();
  143. if (isDbSet)
  144. {
  145. var entityType = prop.PropertyType.GenericTypeArguments[0];
  146. entityTypes.Add(entityType);
  147. }
  148. }
  149. foreach (var table in tables)
  150. {
  151. var res = this.Database.SqlQuery<DbTableColumnInfo>($"PRAGMA table_info([{table}])").ToList();
  152. var entityType = entityTypes.FirstOrDefault(p => p.Name == table);
  153. if (entityType == null) continue;
  154. var entityProps = entityType.GetProperties().Where(p =>
  155. p.CanRead
  156. && p.CanWrite
  157. && !p.GetMethod.IsVirtual
  158. && p.GetCustomAttribute<NotMappedAttribute>() == null);
  159. foreach (var prop in entityProps)
  160. {
  161. var find = res.Find(p => p.name.ToLower() == prop.Name.ToLower());
  162. if (find == null)
  163. {
  164. string typeStr = "";
  165. var type = prop.PropertyType;
  166. if (prop.PropertyType.IsGenericType)
  167. {
  168. type = prop.PropertyType.GenericTypeArguments[0];
  169. }
  170. if (type == typeof(string))
  171. {
  172. typeStr = "nvarchar";
  173. }
  174. else if (type == typeof(int) || type == typeof(long) || prop.PropertyType.IsEnum)
  175. {
  176. typeStr = "int";
  177. }
  178. else if (type == typeof(double) || type == typeof(float))
  179. {
  180. typeStr = "float";
  181. }
  182. else if (type == typeof(DateTime))
  183. {
  184. typeStr = "datetime";
  185. }
  186. else if (type == typeof(bool))
  187. {
  188. typeStr = "int";
  189. }
  190. bool isNullable = prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>);
  191. string updateTableSql;
  192. if (isNullable)
  193. updateTableSql = $"alter table {table} add column {prop.Name} {typeStr}";
  194. else
  195. {
  196. if (typeStr == "int" || typeStr == "float")
  197. updateTableSql = $"alter table {table} add column {prop.Name} {typeStr} not null default 0";
  198. else if (typeStr == "nvarchar")
  199. updateTableSql = $"alter table {table} add column {prop.Name} {typeStr} not null default ''";
  200. else if (typeStr == "datetime")
  201. updateTableSql = $"alter table {table} add column {prop.Name} {typeStr} not null default '{DateTime.Now:yyyy-MM-dd HH:mm:ss}'";
  202. else
  203. updateTableSql = $"alter table {table} add column {prop.Name} {typeStr}";
  204. }
  205. this.Database.ExecuteSqlCommand(updateTableSql);
  206. }
  207. }
  208. }
  209. }
  210. }
  211. }