平安校园
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.
 
 
 
 
 
 

200 rivejä
8.3 KiB

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