UpdateableHelper.cs 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Linq;
  5. using System.Linq.Expressions;
  6. using System.Text;
  7. using System.Text.RegularExpressions;
  8. using System.Threading.Tasks;
  9. namespace SqlSugar
  10. {
  11. public partial class UpdateableProvider<T> : IUpdateable<T> where T : class, new()
  12. {
  13. private bool IsUpdateNullByList()
  14. {
  15. return this.UpdateObjs.Count() > 1 && (this.UpdateBuilder.IsNoUpdateNull || this.UpdateBuilder.IsNoUpdateDefaultValue);
  16. }
  17. private int DatasTrackingExecommand()
  18. {
  19. var trakRows = 0;
  20. var isNoTran = this.Context.Ado.IsNoTran();
  21. try
  22. {
  23. if (isNoTran)
  24. {
  25. this.Context.Ado.BeginTran();
  26. }
  27. int i = 0;
  28. foreach (var item in this.UpdateObjs)
  29. {
  30. var newUpdateable = this.Clone();
  31. (newUpdateable as UpdateableProvider<T>).UpdateObjs = new[] { item };
  32. newUpdateable.UpdateBuilder.IsListUpdate = null;
  33. newUpdateable.UpdateBuilder.DbColumnInfoList =
  34. newUpdateable.UpdateBuilder.DbColumnInfoList.Where(it => it.TableId == i).ToList();
  35. AppendTracking(item, newUpdateable);
  36. if (newUpdateable.UpdateBuilder.DbColumnInfoList?.Any() == true)
  37. {
  38. trakRows += newUpdateable.ExecuteCommand();
  39. }
  40. ++i;
  41. }
  42. if (isNoTran)
  43. {
  44. this.Context.Ado.CommitTran();
  45. }
  46. }
  47. catch (Exception)
  48. {
  49. if (isNoTran)
  50. {
  51. this.Context.Ado.RollbackTran();
  52. }
  53. throw;
  54. }
  55. return trakRows;
  56. }
  57. private async Task<int> DatasTrackingExecommandAsync()
  58. {
  59. var isNoTran = this.Context.Ado.IsNoTran();
  60. var trakRows = 0;
  61. try
  62. {
  63. if (isNoTran)
  64. {
  65. await this.Context.Ado.BeginTranAsync();
  66. }
  67. int i = 0;
  68. foreach (var item in this.UpdateObjs)
  69. {
  70. var newUpdateable = this.Clone();
  71. (newUpdateable as UpdateableProvider<T>).UpdateObjs = new[] { item };
  72. newUpdateable.UpdateBuilder.IsListUpdate = null;
  73. newUpdateable.UpdateBuilder.DbColumnInfoList =
  74. newUpdateable.UpdateBuilder.DbColumnInfoList.Where(it => it.TableId == i).ToList();
  75. AppendTracking(item, newUpdateable);
  76. if (newUpdateable.UpdateBuilder.DbColumnInfoList?.Any() == true)
  77. {
  78. trakRows +=await newUpdateable.ExecuteCommandAsync();
  79. }
  80. ++i;
  81. }
  82. if (isNoTran)
  83. {
  84. await this.Context.Ado.CommitTranAsync();
  85. }
  86. }
  87. catch (Exception)
  88. {
  89. if (isNoTran)
  90. {
  91. await this.Context.Ado.RollbackTranAsync();
  92. }
  93. throw;
  94. }
  95. return trakRows;
  96. }
  97. private bool UpdateObjectNotWhere()
  98. {
  99. return this.Context.CurrentConnectionConfig.DbType != DbType.MySql
  100. && this.Context.CurrentConnectionConfig.DbType != DbType.MySqlConnector
  101. && this.Context.CurrentConnectionConfig.DbType != DbType.SqlServer;
  102. }
  103. private void AppendTracking(T item, IUpdateable<T> newUpdateable)
  104. {
  105. if (IsTrakingData() || IsTrakingDatas())
  106. {
  107. var trackingData = this.Context.TempItems.FirstOrDefault(it => it.Key.StartsWith("Tracking_" + item.GetHashCode()));
  108. var diffColumns = FastCopy.GetDiff(item, (T)trackingData.Value);
  109. if (diffColumns.Count > 0)
  110. {
  111. var pks = EntityInfo.Columns
  112. .Where(it => it.IsPrimarykey).Select(it => it.PropertyName).ToList();
  113. diffColumns = diffColumns.Where(it => !pks.Contains(it)).ToList();
  114. if (diffColumns.Count > 0)
  115. {
  116. newUpdateable.UpdateColumns(diffColumns.ToArray());
  117. }
  118. }
  119. else
  120. {
  121. (newUpdateable as UpdateableProvider<T>).UpdateObjs = new T[] { null };
  122. newUpdateable.UpdateBuilder.DbColumnInfoList = new List<DbColumnInfo>();
  123. }
  124. }
  125. }
  126. private void AppendSets()
  127. {
  128. if (SetColumnsIndex > 0)
  129. {
  130. var keys = UpdateBuilder.SetValues.Select(it => SqlBuilder.GetNoTranslationColumnName(it.Key.ToLower())).ToList();
  131. var addKeys = keys.Where(k => !this.UpdateBuilder.DbColumnInfoList.Any(it => it.PropertyName.ToLower() == k || it.DbColumnName.ToLower() == k)).ToList();
  132. var addItems = this.EntityInfo.Columns.Where(it => !GetPrimaryKeys().Any(p => p.ToLower() == it.PropertyName?.ToLower() || p.ToLower() == it.DbColumnName?.ToLower()) && addKeys.Any(k => it.PropertyName?.ToLower() == k || it.DbColumnName?.ToLower() == k)).ToList();
  133. this.UpdateBuilder.DbColumnInfoList.AddRange(addItems.Select(it => new DbColumnInfo() { PropertyName = it.PropertyName, DbColumnName = it.DbColumnName }));
  134. }
  135. SetColumnsIndex++;
  136. }
  137. private string _ExecuteCommand()
  138. {
  139. CheckWhere();
  140. PreToSql();
  141. AutoRemoveDataCache();
  142. Check.ExceptionEasy(this.UpdateParameterIsNull&&this.UpdateBuilder.DbColumnInfoList.Count() == this.UpdateObjs.Length && this.UpdateObjs.Length==this.UpdateBuilder.DbColumnInfoList.Count(it => it.IsPrimarykey), "The primary key cannot be updated", "主键不能更新,更新主键会对代码逻辑存在未知隐患,如果非要更新:建议你删除在插入或者新建一个没主键的类。");
  143. Check.Exception(UpdateBuilder.WhereValues.IsNullOrEmpty() && GetPrimaryKeys().IsNullOrEmpty(), "You cannot have no primary key and no conditions");
  144. string sql = UpdateBuilder.ToSqlString();
  145. ValidateVersion();
  146. RestoreMapping();
  147. Before(sql);
  148. return sql;
  149. }
  150. private void CheckWhere()
  151. {
  152. if (UpdateParameterIsNull && UpdateBuilder.WhereValues.IsNullOrEmpty())
  153. {
  154. Check.ExceptionEasy("Update requires conditions", "更新需要条件 Where");
  155. }
  156. }
  157. private void _WhereColumn(string columnName)
  158. {
  159. var columnInfos = columns.Where(it => it.DbColumnName.Equals(columnName, StringComparison.OrdinalIgnoreCase) || it.PropertyName.Equals(columnName, StringComparison.OrdinalIgnoreCase)).ToList();
  160. if (!this.UpdateBuilder.DbColumnInfoList.Any(y => y.DbColumnName == columnInfos.First().DbColumnName))
  161. {
  162. this.UpdateBuilder.DbColumnInfoList.AddRange(columnInfos);
  163. }
  164. }
  165. private void AutoRemoveDataCache()
  166. {
  167. var moreSetts = this.Context.CurrentConnectionConfig.MoreSettings;
  168. var extService = this.Context.CurrentConnectionConfig.ConfigureExternalServices;
  169. if (moreSetts != null && moreSetts.IsAutoRemoveDataCache && extService != null && extService.DataInfoCacheService != null)
  170. {
  171. this.RemoveDataCache();
  172. }
  173. }
  174. internal void Init()
  175. {
  176. this.UpdateBuilder.TableName = EntityInfo.EntityName;
  177. if (IsMappingTable)
  178. {
  179. var mappingInfo = this.Context.MappingTables.SingleOrDefault(it => it.EntityName == EntityInfo.EntityName);
  180. if (mappingInfo != null)
  181. {
  182. this.UpdateBuilder.TableName = mappingInfo.DbTableName;
  183. }
  184. }
  185. //Check.Exception(UpdateObjs == null || UpdateObjs.Count() == 0, "UpdateObjs is null");
  186. int i = 0;
  187. if (this.EntityInfo.Columns.Any(it => it.IsPrimarykey))
  188. {
  189. this.UpdateBuilder.OldPrimaryKeys = this.EntityInfo.Columns.Where(it => it.IsPrimarykey).Select(it=>it.DbColumnName).ToList();
  190. }
  191. foreach (var item in UpdateObjs)
  192. {
  193. List<DbColumnInfo> updateItem = new List<DbColumnInfo>();
  194. var isDic = item is Dictionary<string, object>;
  195. if (item is Dictionary<string, string>)
  196. {
  197. Check.ExceptionEasy("To use Updateable dictionary, use string or object", "Updateable字典请使用string,object类型");
  198. }
  199. if (isDic)
  200. {
  201. SetUpdateItemByDic(i, item, updateItem);
  202. }
  203. else
  204. {
  205. DataAop(item);
  206. SetUpdateItemByEntity(i, item, updateItem);
  207. Tracking(item);
  208. }
  209. ++i;
  210. }
  211. this.columns = this.UpdateBuilder.DbColumnInfoList;
  212. var ignoreColumns = EntityInfo.Columns.Where(it => it.IsOnlyIgnoreUpdate).ToList();
  213. if (ignoreColumns != null && ignoreColumns.Any())
  214. {
  215. this.IgnoreColumns(ignoreColumns.Select(it => it.PropertyName).ToArray());
  216. }
  217. }
  218. private void Tracking(T item)
  219. {
  220. if (IsTrakingData())
  221. {
  222. var trackingData = this.Context.TempItems.FirstOrDefault(it => it.Key.StartsWith("Tracking_" + item.GetHashCode()));
  223. if (trackingData.Key == null && trackingData.Value == null)
  224. {
  225. return;
  226. }
  227. var diffColumns = FastCopy.GetDiff(item, (T)trackingData.Value);
  228. if (diffColumns.Count > 0)
  229. {
  230. var pks = EntityInfo.Columns
  231. .Where(it => it.IsPrimarykey).Select(it => it.PropertyName).ToList();
  232. diffColumns = diffColumns.Where(it => !pks.Contains(it)).ToList();
  233. if (diffColumns.Count > 0)
  234. {
  235. this.UpdateColumns(diffColumns.ToArray());
  236. }
  237. }
  238. else
  239. {
  240. this.UpdateObjs = new T [] { null };
  241. this.UpdateBuilder.DbColumnInfoList = new List<DbColumnInfo>();
  242. }
  243. }
  244. }
  245. private bool IsTrakingData()
  246. {
  247. return this.UpdateParameterIsNull == false
  248. && this.Context.TempItems != null
  249. && this.Context.TempItems.Any(it => it.Key.StartsWith("Tracking_"))
  250. && this.UpdateObjs.Length == 1;
  251. }
  252. private bool IsTrakingDatas()
  253. {
  254. return this.UpdateParameterIsNull == false
  255. && this.Context.TempItems != null
  256. && this.Context.TempItems.Any(it => it.Key.StartsWith("Tracking_"))
  257. && this.UpdateObjs.Length > 1;
  258. }
  259. private void DataAop(T item)
  260. {
  261. var dataEvent = this.Context.CurrentConnectionConfig.AopEvents?.DataExecuting;
  262. if (dataEvent != null && item != null)
  263. {
  264. foreach (var columnInfo in this.EntityInfo.Columns)
  265. {
  266. dataEvent(columnInfo.PropertyInfo.GetValue(item, null), new DataFilterModel() { OperationType = DataFilterType.UpdateByObject, EntityValue = item, EntityColumnInfo = columnInfo });
  267. }
  268. }
  269. }
  270. private void CheckTranscodeing(bool checkIsJson = true)
  271. {
  272. if (this.EntityInfo.Columns.Any(it => it.IsTranscoding))
  273. {
  274. Check.Exception(true, ErrorMessage.GetThrowMessage("UpdateColumns no support IsTranscoding", "SetColumns方式更新不支持IsTranscoding,你可以使用db.Updateable(实体)的方式更新"));
  275. }
  276. //if (checkIsJson && this.EntityInfo.Columns.Any(it => it.IsJson))
  277. //{
  278. // Check.Exception(true, ErrorMessage.GetThrowMessage("UpdateColumns no support IsJson", "SetColumns方式更新不支持IsJson,你可以使用db.Updateable(实体)的方式更新"));
  279. //}
  280. //if (this.EntityInfo.Columns.Any(it => it.IsArray))
  281. //{
  282. // Check.Exception(true, ErrorMessage.GetThrowMessage("UpdateColumns no support IsArray", "SetColumns方式更新不支持IsArray,你可以使用db.Updateable(实体)的方式更新"));
  283. //}
  284. }
  285. private void SetUpdateItemByDic(int i, T item, List<DbColumnInfo> updateItem)
  286. {
  287. foreach (var column in (item as Dictionary<string, object>).OrderBy(it=>it.Key))
  288. {
  289. var columnInfo = new DbColumnInfo()
  290. {
  291. Value = column.Value,
  292. DbColumnName = column.Key,
  293. PropertyName = column.Key,
  294. PropertyType = column.Value == null ? DBNull.Value.GetType() : UtilMethods.GetUnderType(column.Value.GetType()),
  295. TableId = i
  296. };
  297. if (columnInfo.PropertyType.IsEnum())
  298. {
  299. if (this.Context.CurrentConnectionConfig.MoreSettings?.TableEnumIsString == true)
  300. {
  301. columnInfo.PropertyType = UtilConstants.StringType;
  302. columnInfo.Value = columnInfo.Value.ToString();
  303. }
  304. else
  305. {
  306. columnInfo.Value = Convert.ToInt64(columnInfo.Value);
  307. }
  308. }
  309. updateItem.Add(columnInfo);
  310. }
  311. this.UpdateBuilder.DbColumnInfoList.AddRange(updateItem);
  312. }
  313. private void SetUpdateItemByEntity(int i, T item, List<DbColumnInfo> updateItem)
  314. {
  315. foreach (var column in EntityInfo.Columns)
  316. {
  317. if (column.IsIgnore) continue;
  318. Check.ExceptionEasy(item == null, "db.Updateable(data) data is required ", "db.Updateable(data) data不能是null");
  319. var columnInfo = new DbColumnInfo()
  320. {
  321. Value = GetValue(item, column),
  322. DbColumnName = GetDbColumnName(column.PropertyName),
  323. PropertyName = column.PropertyName,
  324. PropertyType = UtilMethods.GetUnderType(column.PropertyInfo),
  325. SqlParameterDbType = column.SqlParameterDbType,
  326. TableId = i,
  327. UpdateSql = column.UpdateSql,
  328. UpdateServerTime = column.UpdateServerTime
  329. };
  330. if (columnInfo.PropertyType.IsEnum() && columnInfo.Value != null)
  331. {
  332. if (this.Context.CurrentConnectionConfig.MoreSettings?.TableEnumIsString == true)
  333. {
  334. columnInfo.PropertyType = UtilConstants.StringType;
  335. columnInfo.Value = columnInfo.Value.ToString();
  336. }
  337. else
  338. {
  339. columnInfo.Value = Convert.ToInt64(columnInfo.Value);
  340. }
  341. }
  342. if (column.IsJson)
  343. {
  344. columnInfo.IsJson = true;
  345. if (columnInfo.Value != null)
  346. columnInfo.Value = this.Context.Utilities.SerializeObject(columnInfo.Value);
  347. }
  348. if (column.IsArray)
  349. {
  350. columnInfo.IsArray = true;
  351. }
  352. var tranColumn = EntityInfo.Columns.FirstOrDefault(it => it.IsTranscoding && it.DbColumnName.Equals(column.DbColumnName, StringComparison.CurrentCultureIgnoreCase));
  353. if (tranColumn != null && columnInfo.Value.HasValue())
  354. {
  355. columnInfo.Value = UtilMethods.EncodeBase64(columnInfo.Value.ToString());
  356. }
  357. updateItem.Add(columnInfo);
  358. }
  359. this.UpdateBuilder.DbColumnInfoList.AddRange(updateItem);
  360. }
  361. private static object GetValue(T item, EntityColumnInfo column)
  362. {
  363. if (column.ForOwnsOnePropertyInfo != null)
  364. {
  365. var owsPropertyValue = column.ForOwnsOnePropertyInfo.GetValue(item, null);
  366. return column.PropertyInfo.GetValue(owsPropertyValue, null);
  367. }
  368. else
  369. {
  370. return column.PropertyInfo.GetValue(item, null);
  371. }
  372. }
  373. private void PreToSql()
  374. {
  375. if (this.UpdateBuilder.UpdateColumns.HasValue())
  376. {
  377. var columns = this.UpdateBuilder.UpdateColumns;
  378. this.UpdateBuilder.DbColumnInfoList = this.UpdateBuilder.DbColumnInfoList.Where(it => GetPrimaryKeys().Select(
  379. iit => iit.ToLower()).Contains(it.DbColumnName.ToLower())
  380. || columns.Contains(it.PropertyName, StringComparer.OrdinalIgnoreCase)
  381. || columns.Contains(it.DbColumnName, StringComparer.OrdinalIgnoreCase)).ToList();
  382. }
  383. UpdateBuilder.EntityInfo = this.EntityInfo;
  384. UpdateBuilder.PrimaryKeys = GetPrimaryKeys();
  385. if (this.IsWhereColumns)
  386. {
  387. foreach (var pkName in UpdateBuilder.PrimaryKeys)
  388. {
  389. if (WhereColumnList != null && WhereColumnList.Count() > 0)
  390. {
  391. continue;
  392. }
  393. var isContains = this.UpdateBuilder.DbColumnInfoList.Select(it => it.DbColumnName.ToLower()).Contains(pkName.ToLower());
  394. Check.Exception(isContains == false, "Use UpdateColumns().WhereColumn() ,UpdateColumns need {0}", pkName);
  395. }
  396. }
  397. #region IgnoreColumns
  398. if (this.Context.IgnoreColumns != null && this.Context.IgnoreColumns.Any())
  399. {
  400. var currentIgnoreColumns = this.Context.IgnoreColumns.Where(it => it.EntityName == this.EntityInfo.EntityName).ToList();
  401. this.UpdateBuilder.DbColumnInfoList = this.UpdateBuilder.DbColumnInfoList.Where(it =>
  402. {
  403. return !currentIgnoreColumns.Any(i => it.PropertyName.Equals(i.PropertyName, StringComparison.CurrentCulture));
  404. }).ToList();
  405. }
  406. #endregion
  407. if (this.IsSingle)
  408. {
  409. var isDic = this.EntityInfo.DbTableName.StartsWith("Dictionary`");
  410. foreach (var item in this.UpdateBuilder.DbColumnInfoList)
  411. {
  412. if (this.UpdateBuilder.Parameters == null) this.UpdateBuilder.Parameters = new List<SugarParameter>();
  413. if (this.UpdateBuilder.SetValues.Any(it => this.SqlBuilder.GetNoTranslationColumnName(it.Key) == item.PropertyName))
  414. {
  415. continue;
  416. }
  417. if (item.SqlParameterDbType is Type)
  418. {
  419. continue;
  420. }
  421. var parameter = new SugarParameter(this.SqlBuilder.SqlParameterKeyWord + item.DbColumnName, item.Value, item.PropertyType);
  422. if (item.IsJson)
  423. {
  424. parameter.IsJson = true;
  425. SqlBuilder.ChangeJsonType(parameter);
  426. }
  427. if (item.IsArray)
  428. {
  429. parameter.IsArray = true;
  430. if (parameter.Value == null || parameter.Value == DBNull.Value)
  431. {
  432. ArrayNull(item, parameter);
  433. }
  434. }
  435. if (item.Value == null && isDic)
  436. {
  437. var type = this.SqlBuilder.GetNullType(this.UpdateBuilder.GetTableNameString, item.DbColumnName);
  438. if (type != null)
  439. {
  440. parameter = new SugarParameter(this.SqlBuilder.SqlParameterKeyWord + item.DbColumnName, item.Value, type);
  441. }
  442. }
  443. this.UpdateBuilder.Parameters.Add(parameter);
  444. }
  445. }
  446. #region Identities
  447. List<string> identities = GetIdentityKeys();
  448. if (identities != null && identities.Any())
  449. {
  450. this.UpdateBuilder.DbColumnInfoList.ForEach(it =>
  451. {
  452. var mappingInfo = identities.SingleOrDefault(i => it.DbColumnName.Equals(i, StringComparison.CurrentCultureIgnoreCase));
  453. if (mappingInfo != null && mappingInfo.Any())
  454. {
  455. it.IsIdentity = true;
  456. }
  457. });
  458. }
  459. #endregion
  460. List<string> primaryKey = GetPrimaryKeys();
  461. if (primaryKey != null && primaryKey.Count > 0)
  462. {
  463. this.UpdateBuilder.DbColumnInfoList.ForEach(it =>
  464. {
  465. var mappingInfo = primaryKey.SingleOrDefault(i => it.DbColumnName.Equals(i, StringComparison.CurrentCultureIgnoreCase));
  466. if (mappingInfo != null && mappingInfo.Any())
  467. {
  468. it.IsPrimarykey = true;
  469. }
  470. });
  471. }
  472. if (this.UpdateBuilder.Parameters.HasValue() && this.UpdateBuilder.SetValues.IsValuable())
  473. {
  474. this.UpdateBuilder.Parameters.RemoveAll(it => this.UpdateBuilder.SetValues.Any(v => (SqlBuilder.SqlParameterKeyWord + SqlBuilder.GetNoTranslationColumnName(v.Key)) == it.ParameterName));
  475. }
  476. }
  477. private static void ArrayNull(DbColumnInfo item, SugarParameter parameter)
  478. {
  479. if (item.PropertyType.IsIn(typeof(Guid[]), typeof(Guid?[])))
  480. {
  481. parameter.DbType = System.Data.DbType.Guid;
  482. }
  483. else if (item.PropertyType.IsIn(typeof(int[]), typeof(int?[])))
  484. {
  485. parameter.DbType = System.Data.DbType.Int32;
  486. }
  487. else if (item.PropertyType.IsIn(typeof(long[]), typeof(long?[])))
  488. {
  489. parameter.DbType = System.Data.DbType.Int64;
  490. }
  491. else if (item.PropertyType.IsIn(typeof(short[]), typeof(short?[])))
  492. {
  493. parameter.DbType = System.Data.DbType.Int16;
  494. }
  495. }
  496. private void OptRollBack(int updateRows,T updateData, object oldValue, string name)
  497. {
  498. if (updateRows == 0)
  499. {
  500. var verInfo = this.EntityInfo.Columns.FirstOrDefault(it => it.PropertyName == name);
  501. if (verInfo != null)
  502. {
  503. verInfo.PropertyInfo.SetValue(updateData, oldValue);
  504. }
  505. }
  506. }
  507. private string GetDbColumnName(string propertyName)
  508. {
  509. if (!IsMappingColumns)
  510. {
  511. return propertyName;
  512. }
  513. if (this.Context.MappingColumns.Any(it => it.EntityName.Equals(EntityInfo.EntityName, StringComparison.CurrentCultureIgnoreCase)))
  514. {
  515. this.MappingColumnList = this.Context.MappingColumns.Where(it => it.EntityName.Equals(EntityInfo.EntityName, StringComparison.CurrentCultureIgnoreCase)).ToList();
  516. }
  517. if (MappingColumnList == null || !MappingColumnList.Any())
  518. {
  519. return propertyName;
  520. }
  521. else
  522. {
  523. var mappInfo = this.MappingColumnList.FirstOrDefault(it => it.PropertyName.Equals(propertyName, StringComparison.CurrentCultureIgnoreCase));
  524. return mappInfo == null ? propertyName : mappInfo.DbColumnName;
  525. }
  526. }
  527. private List<string> GetPrimaryKeys()
  528. {
  529. if (this.WhereColumnList.HasValue())
  530. {
  531. return this.WhereColumnList;
  532. }
  533. if (this.Context.IsSystemTablesConfig)
  534. {
  535. return this.Context.DbMaintenance.GetPrimaries(this.Context.EntityMaintenance.GetTableName(this.EntityInfo.EntityName));
  536. }
  537. else
  538. {
  539. return this.EntityInfo.Columns.Where(it => it.IsPrimarykey).Select(it => it.DbColumnName).ToList();
  540. }
  541. }
  542. protected virtual List<string> GetIdentityKeys()
  543. {
  544. if (this.Context.IsSystemTablesConfig)
  545. {
  546. return this.Context.DbMaintenance.GetIsIdentities(this.Context.EntityMaintenance.GetTableName(this.EntityInfo.EntityName));
  547. }
  548. else
  549. {
  550. return this.EntityInfo.Columns.Where(it => it.IsIdentity).Select(it => it.DbColumnName).ToList();
  551. }
  552. }
  553. private void RestoreMapping()
  554. {
  555. if (IsAs)
  556. {
  557. this.Context.MappingTables = OldMappingTableList;
  558. }
  559. }
  560. private void ValidateVersion()
  561. {
  562. var versionColumn = this.EntityInfo.Columns.FirstOrDefault(it => it.IsEnableUpdateVersionValidation);
  563. var pks = this.UpdateBuilder.DbColumnInfoList.Where(it => it.IsPrimarykey).ToList();
  564. if (versionColumn != null && this.IsVersionValidation)
  565. {
  566. Check.Exception(pks.IsNullOrEmpty(), "UpdateVersionValidation the primary key is required.");
  567. List<IConditionalModel> conModels = new List<IConditionalModel>();
  568. foreach (var item in pks)
  569. {
  570. conModels.Add(new ConditionalModel() {CSharpTypeName=item.PropertyType.Name, FieldName = item.DbColumnName, ConditionalType = ConditionalType.Equal, FieldValue = item.Value.ObjToString() });
  571. }
  572. var dbInfo = this.Context.Queryable<T>().Where(conModels).First();
  573. if (dbInfo != null)
  574. {
  575. var currentVersion = this.EntityInfo.Type.GetProperty(versionColumn.PropertyName).GetValue(UpdateObjs.Last(), null);
  576. var dbVersion = this.EntityInfo.Type.GetProperty(versionColumn.PropertyName).GetValue(dbInfo, null);
  577. Check.Exception(currentVersion == null, "UpdateVersionValidation entity property {0} is not null", versionColumn.PropertyName);
  578. Check.Exception(dbVersion == null, "UpdateVersionValidation database column {0} is not null", versionColumn.DbColumnName);
  579. if (versionColumn.PropertyInfo.PropertyType.IsIn(UtilConstants.IntType, UtilConstants.LongType))
  580. {
  581. if (Convert.ToInt64(dbVersion) != Convert.ToInt64(currentVersion))
  582. {
  583. throw new VersionExceptions(string.Format("UpdateVersionValidation {0} Not the latest version ", versionColumn.PropertyName));
  584. }
  585. }
  586. else if (versionColumn.PropertyInfo.PropertyType.IsIn(UtilConstants.DateType))
  587. {
  588. if (dbVersion.ObjToDate() != currentVersion.ObjToDate())
  589. {
  590. throw new VersionExceptions(string.Format("UpdateVersionValidation {0} Not the latest version ", versionColumn.PropertyName));
  591. }
  592. }
  593. else if (versionColumn.PropertyInfo.PropertyType.IsIn(UtilConstants.ByteArrayType))
  594. {
  595. if (UtilMethods.GetLong((byte[])dbVersion) != UtilMethods.GetLong((byte[])currentVersion))
  596. {
  597. throw new VersionExceptions(string.Format("UpdateVersionValidation {0} Not the latest version ", versionColumn.PropertyName));
  598. }
  599. }
  600. else
  601. {
  602. Check.ThrowNotSupportedException(string.Format("UpdateVersionValidation Not Supported Type [ {0} ] , {1}", versionColumn.PropertyInfo.PropertyType, versionColumn.PropertyName));
  603. }
  604. }
  605. }
  606. }
  607. private void After(string sql)
  608. {
  609. if (this.IsEnableDiffLogEvent && !string.IsNullOrEmpty(sql))
  610. {
  611. var isDisableMasterSlaveSeparation = this.Ado.IsDisableMasterSlaveSeparation;
  612. this.Ado.IsDisableMasterSlaveSeparation = true;
  613. var parameters = UpdateBuilder.Parameters;
  614. if (parameters == null)
  615. parameters = new List<SugarParameter>();
  616. diffModel.AfterData = GetDiffTable(sql, parameters);
  617. diffModel.Time = this.Context.Ado.SqlExecutionTime;
  618. if (this.Context.CurrentConnectionConfig.AopEvents.OnDiffLogEvent != null)
  619. this.Context.CurrentConnectionConfig.AopEvents.OnDiffLogEvent(diffModel);
  620. this.Ado.IsDisableMasterSlaveSeparation = isDisableMasterSlaveSeparation;
  621. }
  622. if (this.RemoveCacheFunc != null)
  623. {
  624. this.RemoveCacheFunc();
  625. }
  626. }
  627. private string _ExecuteCommandWithOptLock(T updateData,ref object oldVerValue)
  628. {
  629. Check.ExceptionEasy(UpdateParameterIsNull == true, "Optimistic lock can only be an entity update method", "乐观锁只能是实体更新方式");
  630. var verColumn = this.EntityInfo.Columns.FirstOrDefault(it => it.IsEnableUpdateVersionValidation);
  631. Check.ExceptionEasy(verColumn == null, $" {this.EntityInfo.EntityName } need IsEnableUpdateVersionValidation=true ", $"实体{this.EntityInfo.EntityName}没有找到版本标识特性 IsEnableUpdateVersionValidation");
  632. Check.ExceptionEasy(UpdateObjs.Length > 1, $"Optimistic lock can only handle a single update ", $"乐观锁只能处理单条更新");
  633. Check.ExceptionEasy(!verColumn.UnderType.IsIn(UtilConstants.StringType, UtilConstants.LongType, UtilConstants.GuidType, UtilConstants.DateType), $"Optimistic locks can only be guid, long, and string types", $"乐观锁只能是Guid、Long和字符串类型");
  634. var oldValue = verColumn.PropertyInfo.GetValue(updateData);
  635. oldVerValue = oldValue;
  636. var newValue = UtilMethods.GetRandomByType(verColumn.UnderType);
  637. verColumn.PropertyInfo.SetValue(updateData, newValue);
  638. var data = this.UpdateBuilder.DbColumnInfoList.FirstOrDefault(it =>
  639. it.PropertyName.EqualCase(verColumn.PropertyName));
  640. if (data == null)
  641. {
  642. data = new DbColumnInfo() { DbColumnName= verColumn.DbColumnName,PropertyName=verColumn.PropertyName, Value=newValue };
  643. this.UpdateBuilder.DbColumnInfoList.Add(data);
  644. }
  645. data.Value = newValue;
  646. var pks = GetPrimaryKeys();
  647. Check.ExceptionEasy(pks.Count == 0, "need primary key or WhereColumn", "需要主键或者WhereColumn");
  648. this.Where(verColumn.DbColumnName, "=", oldValue);
  649. foreach (var p in pks)
  650. {
  651. var pkColumn = this.EntityInfo.Columns.FirstOrDefault(
  652. it => it.DbColumnName.EqualCase(p) || it.PropertyName.EqualCase(p));
  653. this.Where(pkColumn.DbColumnName, "=", pkColumn.PropertyInfo.GetValue(updateData));
  654. }
  655. return verColumn.PropertyName;
  656. }
  657. private void Before(string sql)
  658. {
  659. if (this.IsEnableDiffLogEvent&&!string.IsNullOrEmpty(sql))
  660. {
  661. var isDisableMasterSlaveSeparation = this.Ado.IsDisableMasterSlaveSeparation;
  662. this.Ado.IsDisableMasterSlaveSeparation = true;
  663. var parameters = UpdateBuilder.Parameters;
  664. if (parameters == null)
  665. parameters = new List<SugarParameter>();
  666. diffModel.BeforeData = GetDiffTable(sql, parameters);
  667. diffModel.Sql = sql;
  668. diffModel.Parameters = parameters.ToArray();
  669. this.Ado.IsDisableMasterSlaveSeparation = isDisableMasterSlaveSeparation;
  670. }
  671. }
  672. private bool IsPrimaryKey(DbColumnInfo it)
  673. {
  674. var result = GetPrimaryKeys().Any(p => p.Equals(it.DbColumnName, StringComparison.CurrentCultureIgnoreCase) || p.Equals(it.PropertyName, StringComparison.CurrentCultureIgnoreCase));
  675. return result;
  676. }
  677. private List<DiffLogTableInfo> GetDiffTable(string sql, List<SugarParameter> parameters)
  678. {
  679. List<DiffLogTableInfo> result = new List<DiffLogTableInfo>();
  680. DataTable dt = null;
  681. if (this.UpdateParameterIsNull)
  682. {
  683. var whereSql = Regex.Replace(sql, ".* WHERE ", "", RegexOptions.Singleline);
  684. if (IsExists(sql))
  685. {
  686. if (this.UpdateBuilder.SetValues != null)
  687. {
  688. foreach (var item in this.UpdateBuilder.SetValues)
  689. {
  690. if (item.Value?.Contains("SELECT") == true)
  691. {
  692. sql = sql.Replace(item.Value, null);
  693. }
  694. }
  695. }
  696. whereSql = UtilMethods.RemoveBeforeFirstWhere(sql);
  697. }
  698. dt = this.Context.Queryable<T>().AS(this.UpdateBuilder.TableName).Filter(null, true).Where(whereSql).AddParameters(parameters).ToDataTable();
  699. }
  700. else
  701. {
  702. if (this.UpdateObjs.ToList().Count == 0)
  703. {
  704. dt = new DataTable();
  705. }
  706. else if (this.WhereColumnList?.Any() == true)
  707. {
  708. dt = this.Context.Queryable<T>().Filter(null, true).WhereClassByWhereColumns(this.UpdateObjs.ToList(), this.WhereColumnList.ToArray()).ToDataTable();
  709. }
  710. else
  711. {
  712. dt = this.Context.Queryable<T>().Filter(null, true).WhereClassByPrimaryKey(this.UpdateObjs.ToList()).ToDataTable();
  713. }
  714. }
  715. if (dt.Rows != null && dt.Rows.Count > 0)
  716. {
  717. foreach (DataRow row in dt.Rows)
  718. {
  719. DiffLogTableInfo item = new DiffLogTableInfo();
  720. item.TableDescription = this.EntityInfo.TableDescription;
  721. item.TableName = this.EntityInfo.DbTableName;
  722. item.Columns = new List<DiffLogColumnInfo>();
  723. foreach (DataColumn col in dt.Columns)
  724. {
  725. try
  726. {
  727. var sugarColumn = this.EntityInfo.Columns.Where(it => it.DbColumnName != null).First(it =>
  728. it.DbColumnName.Equals(col.ColumnName, StringComparison.CurrentCultureIgnoreCase));
  729. DiffLogColumnInfo addItem = new DiffLogColumnInfo();
  730. addItem.Value = row[col.ColumnName];
  731. addItem.ColumnName = col.ColumnName;
  732. addItem.IsPrimaryKey = sugarColumn.IsPrimarykey;
  733. addItem.ColumnDescription = sugarColumn.ColumnDescription;
  734. item.Columns.Add(addItem);
  735. }
  736. catch (Exception ex)
  737. {
  738. Check.ExceptionEasy(col.ColumnName + " No corresponding entity attribute found in difference log ."+ex.Message, col.ColumnName + "在差异日志中可能没有找到相应的实体属性,详细:"+ex.Message);
  739. }
  740. }
  741. result.Add(item);
  742. }
  743. }
  744. return result;
  745. }
  746. private static bool IsExists(string sql)
  747. {
  748. return UtilMethods.CountSubstringOccurrences(sql,"WHERE")>1;
  749. }
  750. private void ThrowUpdateByExpression()
  751. {
  752. Check.Exception(UpdateParameterIsNull == true, ErrorMessage.GetThrowMessage(" no support UpdateColumns and WhereColumns", "根据表达式更新 db.Updateable<T>() 禁止使用 UpdateColumns和WhereColumns,你可以使用 SetColumns Where 等。更新分为2种方式 1.根据表达式更新 2.根据实体或者集合更新, 具体用法请查看文档 "));
  753. }
  754. private void ThrowUpdateByObject()
  755. {
  756. Check.Exception(UpdateParameterIsNull == false, ErrorMessage.GetThrowMessage(" no support SetColumns and Where", "根据对像更新 db.Updateabe(对象) 禁止使用 SetColumns和Where ,你可以使用WhereColumns 和 UpdateColumns。 更新分为2种方式 1.根据表达式更新 2.根据实体或者集合更新 , 具体用法请查看文档 "));
  757. }
  758. private void ThrowUpdateByExpressionByMesage(string message)
  759. {
  760. Check.Exception(UpdateParameterIsNull == true, ErrorMessage.GetThrowMessage(" no support "+ message, "根据表达式更新 db.Updateable<T>()禁止使用 " + message+"。 更新分为2种方式 1.根据表达式更新 2.根据实体或者集合更新 , 具体用法请查看文档 "));
  761. }
  762. private void ThrowUpdateByObjectByMesage(string message)
  763. {
  764. Check.Exception(UpdateParameterIsNull == false, ErrorMessage.GetThrowMessage(" no support " + message, "根据对象更新 db.Updateable(对象)禁止使用 " + message + "。 更新分为2种方式 1.根据表达式更新 2.根据实体或者集合更新 , 具体用法请查看文档 "));
  765. }
  766. }
  767. }