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.

316 lines
12 KiB

2 years ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace SqlSugar
  8. {
  9. public class DeleteableProvider<T> : IDeleteable<T> where T : class, new()
  10. {
  11. public SqlSugarClient Context { get; set; }
  12. public IAdo Db { get { return Context.Ado; } }
  13. public ISqlBuilder SqlBuilder { get; set; }
  14. public DeleteBuilder DeleteBuilder { get; set; }
  15. public MappingTableList OldMappingTableList { get; set; }
  16. public bool IsAs { get; set; }
  17. public EntityInfo EntityInfo
  18. {
  19. get
  20. {
  21. return this.Context.EntityMaintenance.GetEntityInfo<T>();
  22. }
  23. }
  24. public int ExecuteCommand()
  25. {
  26. DeleteBuilder.EntityInfo = this.Context.EntityMaintenance.GetEntityInfo<T>();
  27. var sql = DeleteBuilder.ToSqlString();
  28. var paramters = DeleteBuilder.Parameters?.ToArray();
  29. RestoreMapping();
  30. AutoRemoveDataCache();
  31. return Db.ExecuteCommand(sql, paramters);
  32. }
  33. public bool ExecuteCommandHasChange()
  34. {
  35. return ExecuteCommand() > 0;
  36. }
  37. public Task<int> ExecuteCommandAsync()
  38. {
  39. var result = new Task<int>(() =>
  40. {
  41. var asyncDeleteable = CopyDeleteable();
  42. return asyncDeleteable.ExecuteCommand();
  43. });
  44. TaskStart(result);
  45. return result;
  46. }
  47. public Task<bool> ExecuteCommandHasChangeAsync()
  48. {
  49. var result = new Task<bool>(() =>
  50. {
  51. var asyncDeleteable = CopyDeleteable();
  52. return asyncDeleteable.ExecuteCommand() > 0;
  53. });
  54. TaskStart(result);
  55. return result;
  56. }
  57. public IDeleteable<T> AS(string tableName)
  58. {
  59. var entityName = typeof(T).Name;
  60. IsAs = true;
  61. OldMappingTableList = this.Context.MappingTables;
  62. this.Context.MappingTables = this.Context.Utilities.TranslateCopy(this.Context.MappingTables);
  63. this.Context.MappingTables.Add(entityName, tableName);
  64. return this; ;
  65. }
  66. public IDeleteable<T> Where(List<T> deleteObjs)
  67. {
  68. if (deleteObjs == null || deleteObjs.Count() == 0)
  69. {
  70. Where(SqlBuilder.SqlFalse);
  71. return this;
  72. }
  73. var tableName = this.Context.EntityMaintenance.GetTableName<T>();
  74. var primaryFields = this.GetPrimaryKeys();
  75. var isSinglePrimaryKey = primaryFields.Count == 1;
  76. Check.Exception(primaryFields.IsNullOrEmpty(), $"Table {tableName} with no primarykey");
  77. if (isSinglePrimaryKey)
  78. {
  79. var primaryKeyValues = new List<object>();
  80. var primaryField = primaryFields.Single();
  81. foreach (var deleteObj in deleteObjs)
  82. {
  83. var entityPropertyName = this.Context.EntityMaintenance.GetPropertyName<T>(primaryField);
  84. var columnInfo = EntityInfo.Columns.Single(it => it.PropertyName.Equals(entityPropertyName, StringComparison.CurrentCultureIgnoreCase));
  85. var value = columnInfo.PropertyInfo.GetValue(deleteObj, null);
  86. primaryKeyValues.Add(value);
  87. }
  88. if (primaryKeyValues.Count < 10000)
  89. {
  90. var inValueString = primaryKeyValues.ToArray().ToJoinSqlInVals();
  91. Where(string.Format(DeleteBuilder.WhereInTemplate, SqlBuilder.GetTranslationColumnName(primaryFields.Single()), inValueString));
  92. }
  93. else
  94. {
  95. if (DeleteBuilder.BigDataInValues == null)
  96. DeleteBuilder.BigDataInValues = new List<object>();
  97. DeleteBuilder.BigDataInValues.AddRange(primaryKeyValues);
  98. DeleteBuilder.BigDataFiled = primaryField;
  99. }
  100. }
  101. else
  102. {
  103. var whereInSql = new StringBuilder();
  104. foreach (var deleteObj in deleteObjs)
  105. {
  106. var orString = new StringBuilder();
  107. var isFirst = deleteObjs.IndexOf(deleteObj) == 0;
  108. if (!isFirst)
  109. {
  110. orString.Append(DeleteBuilder.WhereInOrTemplate + UtilConstants.Space);
  111. }
  112. var i = 0;
  113. var andString = new StringBuilder();
  114. foreach (var primaryField in primaryFields)
  115. {
  116. if (i != 0)
  117. andString.Append(DeleteBuilder.WhereInAndTemplate + UtilConstants.Space);
  118. var entityPropertyName = this.Context.EntityMaintenance.GetPropertyName<T>(primaryField);
  119. var columnInfo = EntityInfo.Columns.Single(it => it.PropertyName == entityPropertyName);
  120. var entityValue = columnInfo.PropertyInfo.GetValue(deleteObj, null);
  121. andString.AppendFormat(DeleteBuilder.WhereInEqualTemplate, primaryField, entityValue);
  122. ++i;
  123. }
  124. orString.AppendFormat(DeleteBuilder.WhereInAreaTemplate, andString);
  125. whereInSql.Append(orString);
  126. }
  127. Where(string.Format(DeleteBuilder.WhereInAreaTemplate, whereInSql.ToString()));
  128. }
  129. return this;
  130. }
  131. public IDeleteable<T> Where(Expression<Func<T, bool>> expression)
  132. {
  133. var expResult = DeleteBuilder.GetExpressionValue(expression, ResolveExpressType.WhereSingle);
  134. DeleteBuilder.WhereInfos.Add(expResult.GetResultString());
  135. return this;
  136. }
  137. public IDeleteable<T> Where(T deleteObj)
  138. {
  139. Check.Exception(GetPrimaryKeys().IsNullOrEmpty(), "Where(entity) Primary key required");
  140. Where(new List<T> { deleteObj });
  141. return this;
  142. }
  143. public IDeleteable<T> Where(string whereString, object parameters = null)
  144. {
  145. DeleteBuilder.WhereInfos.Add(whereString);
  146. if (parameters != null)
  147. {
  148. if (DeleteBuilder.Parameters == null)
  149. {
  150. DeleteBuilder.Parameters = new List<SugarParameter>();
  151. }
  152. DeleteBuilder.Parameters.AddRange(Context.Ado.GetParameters(parameters));
  153. }
  154. return this;
  155. }
  156. public IDeleteable<T> Where(string whereString, SugarParameter parameter)
  157. {
  158. DeleteBuilder.Parameters.Add(parameter);
  159. return this;
  160. }
  161. public IDeleteable<T> Where(string whereString, SugarParameter[] parameters)
  162. {
  163. DeleteBuilder.Parameters.AddRange(parameters);
  164. return this;
  165. }
  166. public IDeleteable<T> Where(string whereString, List<SugarParameter> parameters)
  167. {
  168. DeleteBuilder.Parameters.AddRange(parameters);
  169. return this;
  170. }
  171. public IDeleteable<T> RemoveDataCache()
  172. {
  173. var cacheService = this.Context.CurrentConnectionConfig.ConfigureExternalServices.DataInfoCacheService;
  174. CacheSchemeMain.RemoveCache(cacheService, this.Context.EntityMaintenance.GetTableName<T>());
  175. return this;
  176. }
  177. public IDeleteable<T> In<PkType>(List<PkType> primaryKeyValues)
  178. {
  179. if (primaryKeyValues == null || primaryKeyValues.Count() == 0)
  180. {
  181. Where(SqlBuilder.SqlFalse);
  182. return this;
  183. }
  184. return In<PkType>(primaryKeyValues.ToArray());
  185. }
  186. public IDeleteable<T> In<PkType>(PkType[] primaryKeyValues)
  187. {
  188. if (primaryKeyValues == null || primaryKeyValues.Count() == 0)
  189. {
  190. Where(SqlBuilder.SqlFalse);
  191. return this;
  192. }
  193. var tableName = this.Context.EntityMaintenance.GetTableName<T>();
  194. string primaryField = null;
  195. primaryField = GetPrimaryKeys().FirstOrDefault();
  196. Check.ArgumentNullException(primaryField, "Table " + tableName + " with no primarykey");
  197. if (primaryKeyValues.Length < 10000)
  198. {
  199. Where(string.Format(DeleteBuilder.WhereInTemplate, SqlBuilder.GetTranslationColumnName(primaryField), primaryKeyValues.ToJoinSqlInVals()));
  200. }
  201. else
  202. {
  203. if (DeleteBuilder.BigDataInValues == null)
  204. DeleteBuilder.BigDataInValues = new List<object>();
  205. DeleteBuilder.BigDataInValues.AddRange(primaryKeyValues.Select(it => (object)it));
  206. DeleteBuilder.BigDataFiled = primaryField;
  207. }
  208. return this;
  209. }
  210. public IDeleteable<T> In<PkType>(PkType primaryKeyValue)
  211. {
  212. In(new PkType[] { primaryKeyValue });
  213. return this;
  214. }
  215. public IDeleteable<T> With(string lockString)
  216. {
  217. if (this.Context.CurrentConnectionConfig.DbType == DbType.SqlServer)
  218. DeleteBuilder.TableWithString = lockString;
  219. return this;
  220. }
  221. public KeyValuePair<string, List<SugarParameter>> ToSql()
  222. {
  223. DeleteBuilder.EntityInfo = this.Context.EntityMaintenance.GetEntityInfo<T>();
  224. var sql = DeleteBuilder.ToSqlString();
  225. var paramters = DeleteBuilder.Parameters?.ToList();
  226. RestoreMapping();
  227. return new KeyValuePair<string, List<SugarParameter>>(sql, paramters);
  228. }
  229. private List<string> GetPrimaryKeys()
  230. {
  231. if (this.Context.IsSystemTablesConfig)
  232. {
  233. return this.Context.DbMaintenance.GetPrimaries(this.Context.EntityMaintenance.GetTableName(this.EntityInfo.EntityName));
  234. }
  235. else
  236. {
  237. return this.EntityInfo.Columns.Where(it => it.IsPrimarykey).Select(it => it.DbColumnName).ToList();
  238. }
  239. }
  240. protected virtual List<string> GetIdentityKeys()
  241. {
  242. if (this.Context.IsSystemTablesConfig)
  243. {
  244. return this.Context.DbMaintenance.GetIsIdentities(this.Context.EntityMaintenance.GetTableName(this.EntityInfo.EntityName));
  245. }
  246. else
  247. {
  248. return this.EntityInfo.Columns.Where(it => it.IsIdentity).Select(it => it.DbColumnName).ToList();
  249. }
  250. }
  251. private void RestoreMapping()
  252. {
  253. if (IsAs)
  254. {
  255. this.Context.MappingTables = OldMappingTableList;
  256. }
  257. }
  258. private void TaskStart<Type>(Task<Type> result)
  259. {
  260. if (this.Context.CurrentConnectionConfig.IsShardSameThread)
  261. {
  262. Check.Exception(true, "IsShardSameThread=true can't be used async method");
  263. }
  264. result.Start();
  265. }
  266. private void AutoRemoveDataCache()
  267. {
  268. var moreSetts = this.Context.CurrentConnectionConfig.MoreSettings;
  269. var extService = this.Context.CurrentConnectionConfig.ConfigureExternalServices;
  270. if (moreSetts != null && moreSetts.IsAutoRemoveDataCache && extService != null && extService.DataInfoCacheService != null)
  271. {
  272. this.RemoveDataCache();
  273. }
  274. }
  275. private IDeleteable<T> CopyDeleteable()
  276. {
  277. var asyncContext = this.Context.Utilities.CopyContext(true);
  278. asyncContext.CurrentConnectionConfig.IsAutoCloseConnection = true;
  279. var asyncDeleteable = asyncContext.Deleteable<T>();
  280. var asyncDeleteBuilder = asyncDeleteable.DeleteBuilder;
  281. asyncDeleteBuilder.BigDataFiled = this.DeleteBuilder.BigDataFiled;
  282. asyncDeleteBuilder.BigDataInValues = this.DeleteBuilder.BigDataInValues;
  283. asyncDeleteBuilder.Parameters = this.DeleteBuilder.Parameters;
  284. asyncDeleteBuilder.sql = this.DeleteBuilder.sql;
  285. asyncDeleteBuilder.WhereInfos = this.DeleteBuilder.WhereInfos;
  286. asyncDeleteBuilder.TableWithString = this.DeleteBuilder.TableWithString;
  287. return asyncDeleteable;
  288. }
  289. }
  290. }