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.

277 lines
12 KiB

2 years ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using System.Text;
  6. namespace SqlSugar
  7. {
  8. public partial class CodeFirstProvider : ICodeFirst
  9. {
  10. #region Properties
  11. public virtual SqlSugarClient Context { get; set; }
  12. private bool IsBackupTable { get; set; }
  13. private int MaxBackupDataRows { get; set; }
  14. #endregion Properties
  15. #region Public methods
  16. public virtual ICodeFirst BackupTable(int maxBackupDataRows = int.MaxValue)
  17. {
  18. this.IsBackupTable = true;
  19. this.MaxBackupDataRows = maxBackupDataRows;
  20. return this;
  21. }
  22. public virtual void InitTables(Type entityType)
  23. {
  24. this.Context.Utilities.RemoveCacheAll();
  25. this.Context.InitMppingInfo(entityType);
  26. if (!this.Context.DbMaintenance.IsAnySystemTablePermissions())
  27. {
  28. Check.Exception(true, "Dbfirst and Codefirst requires system table permissions");
  29. }
  30. Check.Exception(this.Context.IsSystemTablesConfig, "Please set SqlSugarClent Parameter ConnectionConfig.InitKeyType=InitKeyType.Attribute ");
  31. var executeResult = Context.Ado.UseTran(() =>
  32. {
  33. Execute(entityType);
  34. });
  35. Check.Exception(!executeResult.IsSuccess, executeResult.ErrorMessage);
  36. }
  37. public virtual void InitTables(Type[] entityTypes)
  38. {
  39. if (entityTypes.HasValue())
  40. {
  41. foreach (var item in entityTypes)
  42. {
  43. InitTables(item);
  44. }
  45. }
  46. }
  47. public virtual void InitTables(string entitiesNamespace)
  48. {
  49. var types = Assembly.Load(entitiesNamespace).GetTypes();
  50. InitTables(types);
  51. }
  52. public virtual void InitTables(params string[] entitiesNamespaces)
  53. {
  54. if (entitiesNamespaces.HasValue())
  55. {
  56. foreach (var item in entitiesNamespaces)
  57. {
  58. InitTables(item);
  59. }
  60. }
  61. }
  62. #endregion Public methods
  63. #region Core Logic
  64. protected virtual void Execute(Type entityType)
  65. {
  66. var entityInfo = this.Context.EntityMaintenance.GetEntityInfo(entityType);
  67. var tableName = GetTableName(entityInfo);
  68. var isAny = this.Context.DbMaintenance.IsAnyTable(tableName);
  69. if (isAny)
  70. ExistLogic(entityInfo);
  71. else
  72. NoExistLogic(entityInfo);
  73. }
  74. public virtual void NoExistLogic(EntityInfo entityInfo)
  75. {
  76. var tableName = GetTableName(entityInfo);
  77. Check.Exception(entityInfo.Columns.Count(it => it.IsPrimarykey) > 1, "Use Code First ,The primary key must not exceed 1");
  78. var columns = new List<DbColumnInfo>();
  79. if (entityInfo.Columns.HasValue())
  80. {
  81. foreach (var item in entityInfo.Columns.Where(it => !it.IsIgnore))
  82. {
  83. var dbColumnInfo = EntityColumnToDbColumn(entityInfo, tableName, item);
  84. columns.Add(dbColumnInfo);
  85. }
  86. }
  87. this.Context.DbMaintenance.CreateTable(tableName, columns);
  88. var pkColumns = entityInfo.Columns.Where(it => it.IsPrimarykey).ToList();
  89. foreach (var item in pkColumns)
  90. {
  91. this.Context.DbMaintenance.AddPrimaryKey(tableName, item.DbColumnName);
  92. }
  93. }
  94. public virtual void ExistLogic(EntityInfo entityInfo)
  95. {
  96. if (entityInfo.Columns.HasValue())
  97. {
  98. Check.Exception(entityInfo.Columns.Count(it => it.IsPrimarykey) > 1, "Use Code First ,The primary key must not exceed 1");
  99. var tableName = GetTableName(entityInfo);
  100. var dbColumns = this.Context.DbMaintenance.GetColumnInfosByTableName(tableName);
  101. ConvertColumns(dbColumns);
  102. var entityColumns = entityInfo.Columns.Where(it => !it.IsIgnore).ToList();
  103. var dropColumns = dbColumns
  104. .Where(dc => !entityColumns.Any(ec => dc.DbColumnName.Equals(ec.OldDbColumnName, StringComparison.CurrentCultureIgnoreCase)))
  105. .Where(dc => !entityColumns.Any(ec => dc.DbColumnName.Equals(ec.DbColumnName, StringComparison.CurrentCultureIgnoreCase)))
  106. .ToList();
  107. var addColumns = entityColumns
  108. .Where(ec => ec.OldDbColumnName.IsNullOrEmpty() || !dbColumns.Any(dc => dc.DbColumnName.Equals(ec.OldDbColumnName, StringComparison.CurrentCultureIgnoreCase)))
  109. .Where(ec => !dbColumns.Any(dc => ec.DbColumnName.Equals(dc.DbColumnName, StringComparison.CurrentCultureIgnoreCase))).ToList();
  110. var alterColumns = entityColumns
  111. .Where(ec => !dbColumns.Any(dc => dc.DbColumnName.Equals(ec.OldDbColumnName, StringComparison.CurrentCultureIgnoreCase)))
  112. .Where(ec =>
  113. dbColumns.Any(dc => dc.DbColumnName.Equals(ec.DbColumnName)
  114. && ((ec.Length != dc.Length && !UtilMethods.GetUnderType(ec.PropertyInfo).IsEnum() && UtilMethods.GetUnderType(ec.PropertyInfo).IsIn(UtilConstants.StringType)) ||
  115. ec.IsNullable != dc.IsNullable ||
  116. IsSamgeType(ec, dc)))).ToList();
  117. var renameColumns = entityColumns
  118. .Where(it => !string.IsNullOrEmpty(it.OldDbColumnName))
  119. .Where(entityColumn => dbColumns.Any(dbColumn => entityColumn.OldDbColumnName.Equals(dbColumn.DbColumnName, StringComparison.CurrentCultureIgnoreCase)))
  120. .ToList();
  121. var isChange = false;
  122. foreach (var item in addColumns)
  123. {
  124. this.Context.DbMaintenance.AddColumn(tableName, EntityColumnToDbColumn(entityInfo, tableName, item));
  125. isChange = true;
  126. }
  127. foreach (var item in dropColumns)
  128. {
  129. this.Context.DbMaintenance.DropColumn(tableName, item.DbColumnName);
  130. isChange = true;
  131. }
  132. foreach (var item in alterColumns)
  133. {
  134. this.Context.DbMaintenance.UpdateColumn(tableName, EntityColumnToDbColumn(entityInfo, tableName, item));
  135. isChange = true;
  136. }
  137. foreach (var item in renameColumns)
  138. {
  139. this.Context.DbMaintenance.RenameColumn(tableName, item.OldDbColumnName, item.DbColumnName);
  140. isChange = true;
  141. }
  142. foreach (var item in entityColumns)
  143. {
  144. var dbColumn = dbColumns.FirstOrDefault(dc => dc.DbColumnName.Equals(item.DbColumnName, StringComparison.CurrentCultureIgnoreCase));
  145. if (dbColumn == null) continue;
  146. var pkDiff = item.IsPrimarykey != dbColumn.IsPrimarykey;
  147. var idEntityDiff = item.IsIdentity != dbColumn.IsIdentity;
  148. if (dbColumn != null && pkDiff && !idEntityDiff)
  149. {
  150. var isAdd = item.IsPrimarykey;
  151. if (isAdd)
  152. {
  153. this.Context.DbMaintenance.AddPrimaryKey(tableName, item.DbColumnName);
  154. }
  155. else
  156. {
  157. this.Context.DbMaintenance.DropConstraint(tableName, string.Format("PK_{0}_{1}", tableName, item.DbColumnName));
  158. }
  159. }
  160. else if (pkDiff || idEntityDiff)
  161. {
  162. ChangeKey(entityInfo, tableName, item);
  163. }
  164. }
  165. if (isChange && IsBackupTable)
  166. {
  167. this.Context.DbMaintenance.BackupTable(tableName, tableName + DateTime.Now.ToString("yyyyMMddHHmmss"), MaxBackupDataRows);
  168. }
  169. }
  170. }
  171. protected virtual void ChangeKey(EntityInfo entityInfo, string tableName, EntityColumnInfo item)
  172. {
  173. var constraintName = string.Format("PK_{0}_{1}", tableName, item.DbColumnName);
  174. if (this.Context.DbMaintenance.IsAnyConstraint(constraintName))
  175. this.Context.DbMaintenance.DropConstraint(tableName, constraintName);
  176. this.Context.DbMaintenance.DropColumn(tableName, item.DbColumnName);
  177. this.Context.DbMaintenance.AddColumn(tableName, EntityColumnToDbColumn(entityInfo, tableName, item));
  178. if (item.IsPrimarykey)
  179. this.Context.DbMaintenance.AddPrimaryKey(tableName, item.DbColumnName);
  180. }
  181. protected virtual void ConvertColumns(List<DbColumnInfo> dbColumns)
  182. {
  183. }
  184. #endregion Core Logic
  185. #region Helper methods
  186. public virtual string GetCreateTableString(EntityInfo entityInfo)
  187. {
  188. var result = new StringBuilder();
  189. var tableName = GetTableName(entityInfo);
  190. return result.ToString();
  191. }
  192. public virtual string GetCreateColumnsString(EntityInfo entityInfo)
  193. {
  194. var result = new StringBuilder();
  195. var tableName = GetTableName(entityInfo);
  196. return result.ToString();
  197. }
  198. protected virtual string GetTableName(EntityInfo entityInfo)
  199. {
  200. return this.Context.EntityMaintenance.GetTableName(entityInfo.EntityName);
  201. }
  202. protected virtual DbColumnInfo EntityColumnToDbColumn(EntityInfo entityInfo, string tableName, EntityColumnInfo item)
  203. {
  204. var propertyType = UtilMethods.GetUnderType(item.PropertyInfo);
  205. var result = new DbColumnInfo
  206. {
  207. TableId = entityInfo.Columns.IndexOf(item),
  208. DbColumnName = item.DbColumnName.HasValue() ? item.DbColumnName : item.PropertyName,
  209. IsPrimarykey = item.IsPrimarykey,
  210. IsIdentity = item.IsIdentity,
  211. TableName = tableName,
  212. IsNullable = item.IsNullable,
  213. DefaultValue = item.DefaultValue,
  214. ColumnDescription = item.ColumnDescription,
  215. Length = item.Length,
  216. DecimalDigits = item.DecimalDigits
  217. };
  218. GetDbType(item, propertyType, result);
  219. return result;
  220. }
  221. protected virtual void GetDbType(EntityColumnInfo item, Type propertyType, DbColumnInfo result)
  222. {
  223. if (!string.IsNullOrEmpty(item.DataType))
  224. {
  225. result.DataType = item.DataType;
  226. }
  227. else if (propertyType.IsEnum())
  228. {
  229. result.DataType = this.Context.Ado.DbBind.GetDbTypeName(item.Length > 9 ? UtilConstants.LongType.Name : UtilConstants.IntType.Name);
  230. }
  231. else
  232. {
  233. result.DataType = this.Context.Ado.DbBind.GetDbTypeName(propertyType.Name);
  234. }
  235. }
  236. protected virtual bool IsSamgeType(EntityColumnInfo ec, DbColumnInfo dc)
  237. {
  238. if (!string.IsNullOrEmpty(ec.DataType))
  239. {
  240. return ec.DataType != dc.DataType;
  241. }
  242. var propertyType = UtilMethods.GetUnderType(ec.PropertyInfo);
  243. var properyTypeName = string.Empty;
  244. properyTypeName = this.Context.Ado.DbBind.GetDbTypeName(propertyType.IsEnum() ? ec.Length > 9 ? UtilConstants.LongType.Name : UtilConstants.IntType.Name : propertyType.Name);
  245. var dataType = dc.DataType;
  246. return properyTypeName != dataType;
  247. }
  248. #endregion Helper methods
  249. }
  250. }