平安校园
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CodeFirstUtils.cs 8.3 KiB

2 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. 
  2. //
  3. using System.Collections;
  4. namespace SafeCampus.SqlSugar;
  5. /// <summary>
  6. /// CodeFirst功能类
  7. /// </summary>
  8. [SuppressSniffer]
  9. public static class CodeFirstUtils
  10. {
  11. /// <summary>
  12. /// CodeFirst生成数据库表结构和种子数据
  13. /// </summary>
  14. /// <param name="options">codefirst选项</param>
  15. /// <param name="assemblyName">程序集名称</param>
  16. public static void CodeFirst(BaseOptions options, string assemblyName)
  17. {
  18. var appName = assemblyName.Split(",")[0];
  19. if (options.InitTable)//如果需要初始化表结构
  20. {
  21. Console.WriteLine($"开始初始化{appName}数据库表结构");
  22. InitTable(assemblyName);
  23. }
  24. if (options.InitSeedData)
  25. {
  26. Console.WriteLine($"开始初始化{appName}数据库种子数据");
  27. InitSeedData(assemblyName);
  28. }
  29. }
  30. /// <summary>
  31. /// 初始化数据库表结构
  32. /// </summary>
  33. /// <param name="assemblyName">程序集名称</param>
  34. private static void InitTable(string assemblyName)
  35. {
  36. // 获取所有实体表-初始化表结构
  37. var entityTypes = App.EffectiveTypes.Where(u =>
  38. !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(SugarTable), false) && u.Assembly.FullName == assemblyName);
  39. if (!entityTypes.Any()) return;//没有就退出
  40. foreach (var entityType in entityTypes)
  41. {
  42. var tenantAtt = entityType.GetCustomAttribute<TenantAttribute>();//获取SqlSugar多租户特性
  43. var ignoreInit = entityType.GetCustomAttribute<IgnoreInitTableAttribute>();//获取忽略初始化特性
  44. if (ignoreInit != null) continue;//如果有忽略初始化特性
  45. if (tenantAtt == null) continue;//如果没有租户特性就下一个
  46. var db = DbContext.DB.GetConnectionScope(tenantAtt.configId.ToString());//获取数据库对象
  47. var splitTable = entityType.GetCustomAttribute<SplitTableAttribute>();//获取自动分表特性
  48. if (splitTable == null)//如果特性是空
  49. db.CodeFirst.InitTables(entityType);//普通创建
  50. else
  51. db.CodeFirst.SplitTables().InitTables(entityType);//自动分表创建
  52. }
  53. }
  54. /// <summary>
  55. /// 初始化种子数据
  56. /// </summary>
  57. /// <param name="assemblyName">程序集名称</param>
  58. private static void InitSeedData(string assemblyName)
  59. {
  60. // 获取所有种子配置-初始化数据
  61. var seedDataTypes = App.EffectiveTypes.Where(u => !u.IsInterface && u is { IsAbstract: false, IsClass: true }
  62. && u.GetInterfaces().Any(i => i.HasImplementedRawGeneric(typeof(ISqlSugarEntitySeedData<>))) && u.Assembly.FullName == assemblyName);
  63. if (!seedDataTypes.Any()) return;
  64. foreach (var seedType in seedDataTypes)//遍历种子类
  65. {
  66. //使用与指定参数匹配程度最高的构造函数来创建指定类型的实例。
  67. var instance = Activator.CreateInstance(seedType);
  68. //获取SeedData方法
  69. var hasDataMethod = seedType.GetMethod("SeedData");
  70. //判断是否有种子数据
  71. var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast<object>();
  72. if (seedData == null) continue;//没有种子数据就下一个
  73. var entityType = seedType.GetInterfaces().First().GetGenericArguments().First();//获取实体类型
  74. var tenantAtt = entityType.GetCustomAttribute<TenantAttribute>();//获取SqlSugar租户特性
  75. if (tenantAtt == null) continue;//如果没有租户特性就下一个
  76. var db = DbContext.DB.GetConnectionScope(tenantAtt.configId.ToString());//获取数据库对象
  77. var config = DbContext.DB_CONFIGS.FirstOrDefault(u => u.ConfigId == tenantAtt.configId.ToString());//获取数据库配置
  78. // var seedDataTable = seedData.ToList().ToDataTable();//获取种子数据:已弃用
  79. var entityInfo = db.EntityMaintenance.GetEntityInfo(entityType);
  80. // seedDataTable.TableName = db.EntityMaintenance.GetEntityInfo(entityType).DbTableName;//获取表名
  81. var ignoreAdd = hasDataMethod.GetCustomAttribute<IgnoreSeedDataAddAttribute>();//读取忽略插入特性
  82. var ignoreUpdate = hasDataMethod.GetCustomAttribute<IgnoreSeedDataUpdateAttribute>();//读取忽略更新特性
  83. if (entityInfo.Columns.Any(u => u.IsPrimarykey))//判断种子数据是否有主键
  84. {
  85. // 按主键进行批量增加和更新
  86. var storage = db.StorageableByObject(seedData.ToList()).ToStorage();
  87. if (ignoreAdd == null) storage.AsInsertable.ExecuteCommand();//执行插入
  88. if (ignoreUpdate == null) storage.AsUpdateable.ExecuteCommand();//只有没有忽略更新的特性才执行更新
  89. }
  90. else// 没有主键或者不是预定义的主键(有重复的可能)
  91. {
  92. //全量插入
  93. // 无主键则只进行插入
  94. if (!db.Queryable(entityInfo.DbTableName, entityInfo.DbTableName).Any() && ignoreAdd == null)
  95. db.InsertableByObject(seedData.ToList()).ExecuteCommand();
  96. }
  97. }
  98. }
  99. /// <summary>
  100. /// 判断类型是否实现某个泛型
  101. /// </summary>
  102. /// <param name="type">类型</param>
  103. /// <param name="generic">泛型类型</param>
  104. /// <returns>bool</returns>
  105. public static bool HasImplementedRawGeneric(this Type type, Type generic)
  106. {
  107. // 检查接口类型
  108. var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);
  109. if (isTheRawGenericType) return true;
  110. // 检查类型
  111. while (type != null && type != typeof(object))
  112. {
  113. isTheRawGenericType = IsTheRawGenericType(type);
  114. if (isTheRawGenericType) return true;
  115. type = type.BaseType ?? default;
  116. }
  117. return false;
  118. // 判断逻辑
  119. bool IsTheRawGenericType(Type type) => generic == (type.IsGenericType ? type.GetGenericTypeDefinition() : type);
  120. }
  121. /// <summary>
  122. /// List转DataTable
  123. /// </summary>
  124. /// <typeparam name="T"></typeparam>
  125. /// <param name="list"></param>
  126. /// <returns></returns>
  127. public static DataTable ToDataTable<T>(this List<T> list)
  128. {
  129. var result = new DataTable();
  130. if (list.Count > 0)
  131. {
  132. // result.TableName = list[0].GetType().Name; // 表名赋值
  133. var propertys = list[0].GetType().GetProperties();
  134. foreach (var pi in propertys)
  135. {
  136. var colType = pi.PropertyType;
  137. if (colType.IsGenericType && colType.GetGenericTypeDefinition() == typeof(Nullable<>))
  138. {
  139. colType = colType.GetGenericArguments()[0];
  140. }
  141. if (IsIgnoreColumn(pi))
  142. continue;
  143. if (IsJsonColumn(pi))//如果是json特性就是sting类型
  144. colType = typeof(string);
  145. result.Columns.Add(pi.Name, colType);
  146. }
  147. for (var i = 0; i < list.Count; i++)
  148. {
  149. var tempList = new ArrayList();
  150. foreach (var pi in propertys)
  151. {
  152. if (IsIgnoreColumn(pi))
  153. continue;
  154. var obj = pi.GetValue(list[i], null);
  155. if (IsJsonColumn(pi))//如果是json特性就是转化为json格式
  156. obj = obj?.ToJson();//如果json字符串是空就传null
  157. tempList.Add(obj);
  158. }
  159. var array = tempList.ToArray();
  160. result.LoadDataRow(array, true);
  161. }
  162. }
  163. return result;
  164. }
  165. /// <summary>
  166. /// 排除SqlSugar忽略的列
  167. /// </summary>
  168. /// <param name="pi"></param>
  169. /// <returns></returns>
  170. private static bool IsIgnoreColumn(PropertyInfo pi)
  171. {
  172. var sc = pi.GetCustomAttributes<SugarColumn>(false).FirstOrDefault(u => u.IsIgnore);
  173. return sc != null;
  174. }
  175. private static bool IsJsonColumn(PropertyInfo pi)
  176. {
  177. var sc = pi.GetCustomAttributes<SugarColumn>(false).FirstOrDefault(u => u.IsJson);
  178. return sc != null;
  179. }
  180. }