UpdateNavOneToMany.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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 partial class UpdateNavProvider<Root, T> where T : class, new() where Root : class, new()
  10. {
  11. public NavigateType? _NavigateType { get; set; }
  12. private void UpdateOneToMany<TChild>(string name, EntityColumnInfo nav) where TChild : class, new()
  13. {
  14. if (_Options?.OneToManyInsertOrUpdate == true)
  15. {
  16. InsertOrUpdate<TChild>(name,nav);
  17. }
  18. else
  19. {
  20. DeleteInsert<TChild>(name, nav);
  21. }
  22. }
  23. private void InsertOrUpdate<TChild>(string name, EntityColumnInfo nav) where TChild : class, new()
  24. {
  25. List<TChild> children = new List<TChild>();
  26. var parentEntity = _ParentEntity;
  27. var parentList = _ParentList;
  28. var parentNavigateProperty = parentEntity.Columns.FirstOrDefault(it => it.PropertyName == name);
  29. var thisEntity = this._Context.EntityMaintenance.GetEntityInfo<TChild>();
  30. var thisPkColumn = GetPkColumnByNav2(thisEntity, nav);
  31. var thisFkColumn = GetFKColumnByNav(thisEntity, nav);
  32. EntityColumnInfo parentPkColumn = GetParentPkColumn();
  33. EntityColumnInfo parentNavColumn = GetParentPkNavColumn(nav);
  34. if (parentNavColumn != null)
  35. {
  36. parentPkColumn = parentNavColumn;
  37. }
  38. if (ParentIsPk(parentNavigateProperty))
  39. {
  40. parentPkColumn = this._ParentEntity.Columns.FirstOrDefault(it => it.IsPrimarykey);
  41. }
  42. var ids = new List<object>();
  43. foreach (var item in parentList)
  44. {
  45. var parentValue = parentPkColumn.PropertyInfo.GetValue(item);
  46. var childs = parentNavigateProperty.PropertyInfo.GetValue(item) as List<TChild>;
  47. if (childs != null)
  48. {
  49. foreach (var child in childs)
  50. {
  51. thisFkColumn.PropertyInfo.SetValue(child, parentValue, null);
  52. }
  53. children.AddRange(childs);
  54. }
  55. ids.Add(parentValue);
  56. if (_Options?.OneToManyNoDeleteNull == true && childs == null)
  57. {
  58. ids.Remove(parentValue);
  59. }
  60. }
  61. if (NotAny(name))
  62. {
  63. DeleteMany(thisEntity, ids, thisFkColumn.DbColumnName);
  64. if (this._Options?.OneToManyEnableLogicDelete == true)
  65. {
  66. var locgicColumn = thisEntity.Columns.FirstOrDefault(it => it.PropertyName.EqualCase("IsDeleted") || it.PropertyName.EqualCase("IsDelete"));
  67. Check.ExceptionEasy(
  68. locgicColumn == null,
  69. thisEntity.EntityName + "Logical deletion requires the entity to have the IsDeleted property",
  70. thisEntity.EntityName + "假删除需要实体有IsDeleted属性");
  71. List<IConditionalModel> conditionalModels = new List<IConditionalModel>();
  72. conditionalModels.Add(new ConditionalModel()
  73. {
  74. FieldName = thisFkColumn.DbColumnName,
  75. FieldValue = string.Join(",", ids.Distinct()),
  76. ConditionalType = ConditionalType.In,
  77. CSharpTypeName = thisFkColumn?.PropertyInfo?.PropertyType?.Name
  78. });
  79. var sqlObj = _Context.Queryable<object>().SqlBuilder.ConditionalModelToSql(conditionalModels);
  80. this._Context.Updateable<object>()
  81. .AS(thisEntity.DbTableName)
  82. .Where(sqlObj.Key, sqlObj.Value)
  83. .SetColumns(locgicColumn.DbColumnName, true)
  84. .ExecuteCommand();
  85. }
  86. else
  87. {
  88. var list=this._Context.Queryable<TChild>()
  89. .AS(thisEntity.DbTableName)
  90. .In(thisFkColumn.DbColumnName, ids.Distinct().ToList())
  91. .ToList();
  92. List<TChild> result = GetNoExistsId(list, children, thisPkColumn.PropertyName);
  93. if (result.Any())
  94. {
  95. this._Context.Deleteable(result).ExecuteCommand();
  96. }
  97. }
  98. _NavigateType = NavigateType.OneToMany;
  99. InsertDatas(children, thisPkColumn);
  100. }
  101. else
  102. {
  103. this._ParentList = children.Cast<object>().ToList();
  104. }
  105. _NavigateType = null;
  106. SetNewParent<TChild>(thisEntity, thisPkColumn);
  107. }
  108. private void DeleteInsert<TChild>(string name, EntityColumnInfo nav) where TChild : class, new()
  109. {
  110. List<TChild> children = new List<TChild>();
  111. var parentEntity = _ParentEntity;
  112. var parentList = _ParentList;
  113. var parentNavigateProperty = parentEntity.Columns.FirstOrDefault(it => it.PropertyName == name);
  114. var thisEntity = this._Context.EntityMaintenance.GetEntityInfo<TChild>();
  115. var thisPkColumn = GetPkColumnByNav2(thisEntity, nav);
  116. var thisFkColumn = GetFKColumnByNav(thisEntity, nav);
  117. EntityColumnInfo parentPkColumn = GetParentPkColumn();
  118. EntityColumnInfo parentNavColumn = GetParentPkNavColumn(nav);
  119. if (parentNavColumn != null)
  120. {
  121. parentPkColumn = parentNavColumn;
  122. }
  123. if (ParentIsPk(parentNavigateProperty))
  124. {
  125. parentPkColumn = this._ParentEntity.Columns.FirstOrDefault(it => it.IsPrimarykey);
  126. }
  127. var ids = new List<object>();
  128. foreach (var item in parentList)
  129. {
  130. var parentValue = parentPkColumn.PropertyInfo.GetValue(item);
  131. var childs = parentNavigateProperty.PropertyInfo.GetValue(item) as List<TChild>;
  132. if (childs != null)
  133. {
  134. foreach (var child in childs)
  135. {
  136. thisFkColumn.PropertyInfo.SetValue(child, parentValue, null);
  137. }
  138. children.AddRange(childs);
  139. }
  140. ids.Add(parentValue);
  141. if (_Options?.OneToManyNoDeleteNull == true && childs == null)
  142. {
  143. ids.Remove(parentValue);
  144. }
  145. }
  146. if (NotAny(name))
  147. {
  148. DeleteMany(thisEntity, ids, thisFkColumn.DbColumnName);
  149. if (this._Options?.OneToManyEnableLogicDelete == true)
  150. {
  151. var locgicColumn = thisEntity.Columns.FirstOrDefault(it => it.PropertyName.EqualCase("IsDeleted") || it.PropertyName.EqualCase("IsDelete"));
  152. Check.ExceptionEasy(
  153. locgicColumn == null,
  154. thisEntity.EntityName + "Logical deletion requires the entity to have the IsDeleted property",
  155. thisEntity.EntityName + "假删除需要实体有IsDeleted属性");
  156. List<IConditionalModel> conditionalModels = new List<IConditionalModel>();
  157. conditionalModels.Add(new ConditionalModel()
  158. {
  159. FieldName = thisFkColumn.DbColumnName,
  160. FieldValue = string.Join(",", ids.Distinct()),
  161. ConditionalType = ConditionalType.In,
  162. CSharpTypeName = thisFkColumn?.PropertyInfo?.PropertyType?.Name
  163. });
  164. var sqlObj = _Context.Queryable<object>().SqlBuilder.ConditionalModelToSql(conditionalModels);
  165. this._Context.Updateable<object>()
  166. .AS(thisEntity.DbTableName)
  167. .Where(sqlObj.Key, sqlObj.Value)
  168. .SetColumns(locgicColumn.DbColumnName, true)
  169. .ExecuteCommand();
  170. }
  171. else
  172. {
  173. if (this._Context?.CurrentConnectionConfig?.MoreSettings?.IsAutoDeleteQueryFilter == true)
  174. {
  175. this._Context.Deleteable<object>()
  176. .AS(thisEntity.DbTableName)
  177. .EnableQueryFilter(thisEntity.Type)
  178. .In(thisFkColumn.DbColumnName, ids.Distinct().ToList()).ExecuteCommand();
  179. }
  180. else
  181. {
  182. this._Context.Deleteable<object>()
  183. .AS(thisEntity.DbTableName)
  184. .In(thisFkColumn.DbColumnName, ids.Distinct().ToList()).ExecuteCommand();
  185. }
  186. }
  187. _NavigateType = NavigateType.OneToMany;
  188. InsertDatas(children, thisPkColumn);
  189. }
  190. else
  191. {
  192. this._ParentList = children.Cast<object>().ToList();
  193. }
  194. _NavigateType = null;
  195. SetNewParent<TChild>(thisEntity, thisPkColumn);
  196. }
  197. private static bool ParentIsPk(EntityColumnInfo parentNavigateProperty)
  198. {
  199. return parentNavigateProperty != null &&
  200. parentNavigateProperty.Navigat != null &&
  201. parentNavigateProperty.Navigat.NavigatType == NavigateType.OneToMany &&
  202. parentNavigateProperty.Navigat.Name2 == null;
  203. }
  204. private void DeleteMany(EntityInfo thisEntity, List<object> ids,string fkName)
  205. {
  206. if (_Options == null||_Options.OneToManyDeleteAll==false)
  207. {
  208. return;
  209. }
  210. var oneToManys = thisEntity.Columns.Where(it => it.Navigat != null && it.Navigat.NavigatType == NavigateType.OneToMany).ToList();
  211. foreach (var oneToMany in oneToManys)
  212. {
  213. var fkFieldName = oneToMany.Navigat.Name2 ?? thisEntity.Columns.FirstOrDefault(it => it.IsPrimarykey).PropertyName;
  214. var fkDbColumnName = thisEntity.Columns.FirstOrDefault(it => it.PropertyName == fkFieldName).DbColumnName;
  215. var fks = this._Context.Queryable<object>()
  216. .AS(thisEntity.DbTableName)
  217. .In(fkName, ids.Distinct().ToList()).Select(fkDbColumnName).ToDataTable().Rows.Cast<System.Data.DataRow>().Select(x => x[0]).ToArray();
  218. var type = oneToMany.PropertyInfo.PropertyType.GenericTypeArguments[0];
  219. var entity = this._Context.EntityMaintenance.GetEntityInfo(type);
  220. var id = oneToMany.Navigat.Name;
  221. var column = entity.Columns.FirstOrDefault(it => it.PropertyName == id).DbColumnName;
  222. DeleteChild(fks, entity, column);
  223. this._Context.Deleteable<object>()
  224. .AS(entity.DbTableName)
  225. .In(column, fks.Distinct().ToList()).ExecuteCommand();
  226. }
  227. }
  228. private void DeleteChild(object[] fks, EntityInfo entity, string column)
  229. {
  230. var childs = entity.Columns.Where(it => it.Navigat != null && it.Navigat?.NavigatType == NavigateType.OneToMany).ToList();
  231. if (childs.Any())
  232. {
  233. var pkColumn = entity.Columns.First(it => it.IsPrimarykey);
  234. var pkIds = this._Context.Queryable<object>()
  235. .AS(entity.DbTableName)
  236. .In(column, fks.Distinct().ToList())
  237. .Select(pkColumn.DbColumnName).ToDataTable().Rows
  238. .Cast<System.Data.DataRow>().Select(it => it[0]).ToList();
  239. DeleteChildChild(pkIds, childs);
  240. }
  241. }
  242. int childIndex = 0;
  243. private void DeleteChildChild(List<object> ids, List<EntityColumnInfo> childs)
  244. {
  245. childIndex++;
  246. if (childIndex > 4)
  247. {
  248. Check.ExceptionEasy("Removing too many levels", "安全机制限制删除脏数据层级不能超过7层");
  249. }
  250. foreach (var columnInfo in childs)
  251. {
  252. var navigat = columnInfo.Navigat;
  253. var type = columnInfo.PropertyInfo.PropertyType.GenericTypeArguments[0];
  254. var thisEntity = this._Context.EntityMaintenance.GetEntityInfo(type);
  255. var fkColumn = thisEntity.Columns.FirstOrDefault(it => navigat.Name.EqualCase(it.PropertyName));
  256. var thisPkColumn = thisEntity.Columns.FirstOrDefault(it => it.IsPrimarykey);
  257. var childs2 = thisEntity.Columns.Where(it => it.Navigat != null && it.Navigat?.NavigatType == NavigateType.OneToMany).ToList(); ;
  258. if (childs2.Any())
  259. {
  260. var pkIds = _Context.Queryable<object>().AS(thisEntity.DbTableName)
  261. .In(fkColumn.DbColumnName, ids)
  262. .Select(thisPkColumn.DbColumnName).ToDataTable().Rows
  263. .Cast<System.Data.DataRow>().Select(it => it[0]).ToList();
  264. DeleteChildChild(pkIds, childs2);
  265. }
  266. _Context.Deleteable<object>().AS(thisEntity.DbTableName).In(fkColumn.DbColumnName, ids).ExecuteCommand();
  267. }
  268. }
  269. private EntityColumnInfo GetParentPkColumn()
  270. {
  271. EntityColumnInfo parentPkColumn = _ParentPkColumn;
  272. if (_ParentPkColumn == null)
  273. {
  274. parentPkColumn = _ParentPkColumn = this._ParentEntity.Columns.FirstOrDefault(it => it.IsPrimarykey);
  275. }
  276. return parentPkColumn;
  277. }
  278. private EntityColumnInfo GetParentPkNavColumn(EntityColumnInfo nav)
  279. {
  280. EntityColumnInfo result = null;
  281. if (nav.Navigat.Name2.HasValue())
  282. {
  283. result = _ParentPkColumn = this._ParentEntity.Columns.FirstOrDefault(it => it.PropertyName == nav.Navigat.Name2);
  284. }
  285. return result;
  286. }
  287. private void SetNewParent<TChild>(EntityInfo entityInfo, EntityColumnInfo entityColumnInfo) where TChild : class, new()
  288. {
  289. this._ParentEntity = entityInfo;
  290. this._ParentPkColumn = entityColumnInfo;
  291. }
  292. public List<TChild> GetNoExistsId<TChild>(List<TChild> old, List<TChild> newList, string pkName)
  293. {
  294. List<TChild> result = new List<TChild>();
  295. // 将newList中的主键属性转换为字符串集合
  296. var newIds = newList.Select(item => GetPropertyValueAsString(item, pkName)).ToList();
  297. // 获取在old中但不在newList中的主键属性值
  298. result = old.Where(item => !newIds.Contains(GetPropertyValueAsString(item, pkName)))
  299. .ToList();
  300. return result;
  301. }
  302. // 获取对象的属性值
  303. private string GetPropertyValueAsString<TChild>(TChild item, string propertyName)
  304. {
  305. var property = item.GetType().GetProperty(propertyName);
  306. if (property != null)
  307. {
  308. return property.GetValue(item, null)+"";
  309. }
  310. else
  311. {
  312. throw new ArgumentException($"Property '{propertyName}' not found on type {item.GetType().Name}");
  313. }
  314. }
  315. }
  316. }