using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace SqlSugar { public partial class UpdateNavProvider where T : class, new() where Root : class, new() { public NavigateType? _NavigateType { get; set; } private void UpdateOneToMany(string name, EntityColumnInfo nav) where TChild : class, new() { if (_Options?.OneToManyInsertOrUpdate == true) { InsertOrUpdate(name,nav); } else { DeleteInsert(name, nav); } } private void InsertOrUpdate(string name, EntityColumnInfo nav) where TChild : class, new() { List children = new List(); var parentEntity = _ParentEntity; var parentList = _ParentList; var parentNavigateProperty = parentEntity.Columns.FirstOrDefault(it => it.PropertyName == name); var thisEntity = this._Context.EntityMaintenance.GetEntityInfo(); var thisPkColumn = GetPkColumnByNav2(thisEntity, nav); var thisFkColumn = GetFKColumnByNav(thisEntity, nav); EntityColumnInfo parentPkColumn = GetParentPkColumn(); EntityColumnInfo parentNavColumn = GetParentPkNavColumn(nav); if (parentNavColumn != null) { parentPkColumn = parentNavColumn; } if (ParentIsPk(parentNavigateProperty)) { parentPkColumn = this._ParentEntity.Columns.FirstOrDefault(it => it.IsPrimarykey); } var ids = new List(); foreach (var item in parentList) { var parentValue = parentPkColumn.PropertyInfo.GetValue(item); var childs = parentNavigateProperty.PropertyInfo.GetValue(item) as List; if (childs != null) { foreach (var child in childs) { thisFkColumn.PropertyInfo.SetValue(child, parentValue, null); } children.AddRange(childs); } ids.Add(parentValue); if (_Options?.OneToManyNoDeleteNull == true && childs == null) { ids.Remove(parentValue); } } if (NotAny(name)) { DeleteMany(thisEntity, ids, thisFkColumn.DbColumnName); if (this._Options?.OneToManyEnableLogicDelete == true) { var locgicColumn = thisEntity.Columns.FirstOrDefault(it => it.PropertyName.EqualCase("IsDeleted") || it.PropertyName.EqualCase("IsDelete")); Check.ExceptionEasy( locgicColumn == null, thisEntity.EntityName + "Logical deletion requires the entity to have the IsDeleted property", thisEntity.EntityName + "假删除需要实体有IsDeleted属性"); List conditionalModels = new List(); conditionalModels.Add(new ConditionalModel() { FieldName = thisFkColumn.DbColumnName, FieldValue = string.Join(",", ids.Distinct()), ConditionalType = ConditionalType.In, CSharpTypeName = thisFkColumn?.PropertyInfo?.PropertyType?.Name }); var sqlObj = _Context.Queryable().SqlBuilder.ConditionalModelToSql(conditionalModels); this._Context.Updateable() .AS(thisEntity.DbTableName) .Where(sqlObj.Key, sqlObj.Value) .SetColumns(locgicColumn.DbColumnName, true) .ExecuteCommand(); } else { var list=this._Context.Queryable() .AS(thisEntity.DbTableName) .In(thisFkColumn.DbColumnName, ids.Distinct().ToList()) .ToList(); List result = GetNoExistsId(list, children, thisPkColumn.PropertyName); if (result.Any()) { this._Context.Deleteable(result).ExecuteCommand(); } } _NavigateType = NavigateType.OneToMany; InsertDatas(children, thisPkColumn); } else { this._ParentList = children.Cast().ToList(); } _NavigateType = null; SetNewParent(thisEntity, thisPkColumn); } private void DeleteInsert(string name, EntityColumnInfo nav) where TChild : class, new() { List children = new List(); var parentEntity = _ParentEntity; var parentList = _ParentList; var parentNavigateProperty = parentEntity.Columns.FirstOrDefault(it => it.PropertyName == name); var thisEntity = this._Context.EntityMaintenance.GetEntityInfo(); var thisPkColumn = GetPkColumnByNav2(thisEntity, nav); var thisFkColumn = GetFKColumnByNav(thisEntity, nav); EntityColumnInfo parentPkColumn = GetParentPkColumn(); EntityColumnInfo parentNavColumn = GetParentPkNavColumn(nav); if (parentNavColumn != null) { parentPkColumn = parentNavColumn; } if (ParentIsPk(parentNavigateProperty)) { parentPkColumn = this._ParentEntity.Columns.FirstOrDefault(it => it.IsPrimarykey); } var ids = new List(); foreach (var item in parentList) { var parentValue = parentPkColumn.PropertyInfo.GetValue(item); var childs = parentNavigateProperty.PropertyInfo.GetValue(item) as List; if (childs != null) { foreach (var child in childs) { thisFkColumn.PropertyInfo.SetValue(child, parentValue, null); } children.AddRange(childs); } ids.Add(parentValue); if (_Options?.OneToManyNoDeleteNull == true && childs == null) { ids.Remove(parentValue); } } if (NotAny(name)) { DeleteMany(thisEntity, ids, thisFkColumn.DbColumnName); if (this._Options?.OneToManyEnableLogicDelete == true) { var locgicColumn = thisEntity.Columns.FirstOrDefault(it => it.PropertyName.EqualCase("IsDeleted") || it.PropertyName.EqualCase("IsDelete")); Check.ExceptionEasy( locgicColumn == null, thisEntity.EntityName + "Logical deletion requires the entity to have the IsDeleted property", thisEntity.EntityName + "假删除需要实体有IsDeleted属性"); List conditionalModels = new List(); conditionalModels.Add(new ConditionalModel() { FieldName = thisFkColumn.DbColumnName, FieldValue = string.Join(",", ids.Distinct()), ConditionalType = ConditionalType.In, CSharpTypeName = thisFkColumn?.PropertyInfo?.PropertyType?.Name }); var sqlObj = _Context.Queryable().SqlBuilder.ConditionalModelToSql(conditionalModels); this._Context.Updateable() .AS(thisEntity.DbTableName) .Where(sqlObj.Key, sqlObj.Value) .SetColumns(locgicColumn.DbColumnName, true) .ExecuteCommand(); } else { if (this._Context?.CurrentConnectionConfig?.MoreSettings?.IsAutoDeleteQueryFilter == true) { this._Context.Deleteable() .AS(thisEntity.DbTableName) .EnableQueryFilter(thisEntity.Type) .In(thisFkColumn.DbColumnName, ids.Distinct().ToList()).ExecuteCommand(); } else { this._Context.Deleteable() .AS(thisEntity.DbTableName) .In(thisFkColumn.DbColumnName, ids.Distinct().ToList()).ExecuteCommand(); } } _NavigateType = NavigateType.OneToMany; InsertDatas(children, thisPkColumn); } else { this._ParentList = children.Cast().ToList(); } _NavigateType = null; SetNewParent(thisEntity, thisPkColumn); } private static bool ParentIsPk(EntityColumnInfo parentNavigateProperty) { return parentNavigateProperty != null && parentNavigateProperty.Navigat != null && parentNavigateProperty.Navigat.NavigatType == NavigateType.OneToMany && parentNavigateProperty.Navigat.Name2 == null; } private void DeleteMany(EntityInfo thisEntity, List ids,string fkName) { if (_Options == null||_Options.OneToManyDeleteAll==false) { return; } var oneToManys = thisEntity.Columns.Where(it => it.Navigat != null && it.Navigat.NavigatType == NavigateType.OneToMany).ToList(); foreach (var oneToMany in oneToManys) { var fkFieldName = oneToMany.Navigat.Name2 ?? thisEntity.Columns.FirstOrDefault(it => it.IsPrimarykey).PropertyName; var fkDbColumnName = thisEntity.Columns.FirstOrDefault(it => it.PropertyName == fkFieldName).DbColumnName; var fks = this._Context.Queryable() .AS(thisEntity.DbTableName) .In(fkName, ids.Distinct().ToList()).Select(fkDbColumnName).ToDataTable().Rows.Cast().Select(x => x[0]).ToArray(); var type = oneToMany.PropertyInfo.PropertyType.GenericTypeArguments[0]; var entity = this._Context.EntityMaintenance.GetEntityInfo(type); var id = oneToMany.Navigat.Name; var column = entity.Columns.FirstOrDefault(it => it.PropertyName == id).DbColumnName; DeleteChild(fks, entity, column); this._Context.Deleteable() .AS(entity.DbTableName) .In(column, fks.Distinct().ToList()).ExecuteCommand(); } } private void DeleteChild(object[] fks, EntityInfo entity, string column) { var childs = entity.Columns.Where(it => it.Navigat != null && it.Navigat?.NavigatType == NavigateType.OneToMany).ToList(); if (childs.Any()) { var pkColumn = entity.Columns.First(it => it.IsPrimarykey); var pkIds = this._Context.Queryable() .AS(entity.DbTableName) .In(column, fks.Distinct().ToList()) .Select(pkColumn.DbColumnName).ToDataTable().Rows .Cast().Select(it => it[0]).ToList(); DeleteChildChild(pkIds, childs); } } int childIndex = 0; private void DeleteChildChild(List ids, List childs) { childIndex++; if (childIndex > 4) { Check.ExceptionEasy("Removing too many levels", "安全机制限制删除脏数据层级不能超过7层"); } foreach (var columnInfo in childs) { var navigat = columnInfo.Navigat; var type = columnInfo.PropertyInfo.PropertyType.GenericTypeArguments[0]; var thisEntity = this._Context.EntityMaintenance.GetEntityInfo(type); var fkColumn = thisEntity.Columns.FirstOrDefault(it => navigat.Name.EqualCase(it.PropertyName)); var thisPkColumn = thisEntity.Columns.FirstOrDefault(it => it.IsPrimarykey); var childs2 = thisEntity.Columns.Where(it => it.Navigat != null && it.Navigat?.NavigatType == NavigateType.OneToMany).ToList(); ; if (childs2.Any()) { var pkIds = _Context.Queryable().AS(thisEntity.DbTableName) .In(fkColumn.DbColumnName, ids) .Select(thisPkColumn.DbColumnName).ToDataTable().Rows .Cast().Select(it => it[0]).ToList(); DeleteChildChild(pkIds, childs2); } _Context.Deleteable().AS(thisEntity.DbTableName).In(fkColumn.DbColumnName, ids).ExecuteCommand(); } } private EntityColumnInfo GetParentPkColumn() { EntityColumnInfo parentPkColumn = _ParentPkColumn; if (_ParentPkColumn == null) { parentPkColumn = _ParentPkColumn = this._ParentEntity.Columns.FirstOrDefault(it => it.IsPrimarykey); } return parentPkColumn; } private EntityColumnInfo GetParentPkNavColumn(EntityColumnInfo nav) { EntityColumnInfo result = null; if (nav.Navigat.Name2.HasValue()) { result = _ParentPkColumn = this._ParentEntity.Columns.FirstOrDefault(it => it.PropertyName == nav.Navigat.Name2); } return result; } private void SetNewParent(EntityInfo entityInfo, EntityColumnInfo entityColumnInfo) where TChild : class, new() { this._ParentEntity = entityInfo; this._ParentPkColumn = entityColumnInfo; } public List GetNoExistsId(List old, List newList, string pkName) { List result = new List(); // 将newList中的主键属性转换为字符串集合 var newIds = newList.Select(item => GetPropertyValueAsString(item, pkName)).ToList(); // 获取在old中但不在newList中的主键属性值 result = old.Where(item => !newIds.Contains(GetPropertyValueAsString(item, pkName))) .ToList(); return result; } // 获取对象的属性值 private string GetPropertyValueAsString(TChild item, string propertyName) { var property = item.GetType().GetProperty(propertyName); if (property != null) { return property.GetValue(item, null)+""; } else { throw new ArgumentException($"Property '{propertyName}' not found on type {item.GetType().Name}"); } } } }