using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Primitives; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; using System.Text.Json.Serialization; using WalkingTec.Mvvm.Core.Extensions; using WalkingTec.Mvvm.Core.Support.FileHandlers; namespace WalkingTec.Mvvm.Core { /// /// 批量操作VM接口 /// /// 批量修改的VM public interface IBaseBatchVM where TEditModel : BaseVM { /// /// 批量修改的VM /// TEditModel LinkedVM { get; } /// /// 批量列表VM /// IBasePagedListVM ListVM { get; } /// /// 列表数据的Id数组 /// //IEnumerable Ids { get; set; } string[] Ids { get; set; } /// /// 批量操作的错误 /// Dictionary ErrorMessage { get; set; } } /// /// 批量操作的基础VM,所有批量操作的VM应继承本类 /// /// 批量修改的VM /// 批量列表VM public class BaseBatchVM : BaseVM, IBaseBatchVM where TModel : TopBasePoco,new() where TLinkModel : BaseVM { /// /// 批量修改的VM /// public TLinkModel LinkedVM { get; set; } /// /// 批量列表VM /// [JsonIgnore] public IBasePagedListVM ListVM { get; set; } /// /// 批量操作的错误 /// [JsonIgnore] public Dictionary ErrorMessage { get; set; } /// /// 列表数据的Id数组 /// public string[] Ids { get; set; } /// /// 构造函数 /// public BaseBatchVM() { //this.Ids = new List(); ErrorMessage = new Dictionary(); } /// /// 添加错误信息 /// /// 错误 /// 数据Id protected void SetExceptionMessage(Exception e, string id) { if (id != null) { ErrorMessage.Add(id, e.Message); } } /// /// 检查是否可以删除,当进行批量删除操作时会调用本函数。子类如果有特殊判断应重载本函数 /// /// 数据Id /// 错误信息 /// true代表可以删除,false代表不能删除 protected virtual bool CheckIfCanDelete(object id, out string errorMessage) { errorMessage = null; return true; } /// /// 批量删除,默认对Ids中包含的主键的数据进行删除。子类如果有特殊判断应重载本函数 /// /// true代表成功,false代表失败 public virtual bool DoBatchDelete() { bool rv = true; //循环所有数据Id List idsData = Ids.ToList(); var modelType = typeof(TModel); var pros = modelType.GetAllProperties(); //如果包含附件,则先删除附件 List fileids = new List(); var fa = pros.Where(x => x.PropertyType == typeof(FileAttachment) || typeof(TopBasePoco).IsAssignableFrom(x.PropertyType)).ToList(); var isPersist =typeof(IPersistPoco).IsAssignableFrom(modelType); var isBasePoco = typeof(IBasePoco).IsAssignableFrom(modelType); var query = DC.Set().AsQueryable(); var fas = pros.Where(x => typeof(IEnumerable).IsAssignableFrom(x.PropertyType)).ToList(); foreach (var f in fas) { query = query.Include(f.Name); } query = query.AsNoTracking().CheckIDs(idsData); var entityList = query.ToList(); for (int i = 0; i < entityList.Count; i++) { string checkErro = null; //检查是否可以删除,如不能删除则直接跳过 if (CheckIfCanDelete(idsData[i], out checkErro) == false) { ErrorMessage.Add(idsData[i], checkErro); rv = false; break; } //进行删除 try { var Entity = entityList[i]; if (isPersist) { (Entity as IPersistPoco).IsValid = false; DC.UpdateProperty(Entity, "IsValid"); if (isBasePoco) { (Entity as IBasePoco).UpdateTime = DateTime.Now; (Entity as IBasePoco).UpdateBy = LoginUserInfo.ITCode; DC.UpdateProperty(Entity, "UpdateTime"); DC.UpdateProperty(Entity, "UpdateBy"); } } else { foreach (var f in fa) { if (f.PropertyType == typeof(FileAttachment)) { string fidfield = DC.GetFKName2(modelType, f.Name); var fidpro = pros.Where(x => x.Name == fidfield).FirstOrDefault(); var idresult = fidpro.GetValue(Entity); if(idresult != null) { Guid fid = Guid.Empty; if(Guid.TryParse(idresult.ToString(), out fid) == true) { fileids.Add(fid); } } } f.SetValue(Entity, null); } foreach (var f in fas) { var subs = f.GetValue(Entity) as IEnumerable; if (subs != null) { foreach (var sub in subs) { fileids.Add(sub.FileId); } f.SetValue(Entity, null); } else { } } if (typeof(TModel) != typeof(FileAttachment)) { foreach (var pro in pros) { if (pro.PropertyType.GetTypeInfo().IsSubclassOf(typeof(TopBasePoco))) { pro.SetValue(Entity, null); } } } DC.DeleteEntity(Entity); } } catch (Exception e) { SetExceptionMessage(e, idsData[i]); rv = false; } } //进行数据库的删除操作 if (rv == true) { try { DC.SaveChanges(); var fp = Wtm.ServiceProvider.GetRequiredService(); foreach (var item in fileids) { fp.DeleteFile(item.ToString(), DC.ReCreate()); } } catch (Exception e) { SetExceptionMessage(e, null); rv = false; } } //如果失败,添加错误信息 if (rv == false) { if (ErrorMessage.Count > 0) { foreach (var id in idsData) { if (!ErrorMessage.ContainsKey(id)) { ErrorMessage.Add(id, CoreProgram._localizer?["Sys.Rollback"]); } } } ListVM?.DoSearch(); if (ListVM != null) { foreach (var item in ListVM?.GetEntityList()) { item.BatchError = ErrorMessage.Where(x => x.Key == item.GetID().ToString()).Select(x => x.Value).FirstOrDefault(); } } MSD.AddModelError("", CoreProgram._localizer?["Sys.DataCannotDelete"]); } return rv; } /// /// 批量修改,默认对Ids中包含的数据进行修改,子类如果有特殊判断应重载本函数 /// /// true代表成功,false代表失败 public virtual bool DoBatchEdit() { //获取批量修改VM的所有属性 var pros = LinkedVM.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly); bool rv = true; List idsData = Ids.ToList(); string currentvmname = this.GetType().Name; Type vmtype = null; //找到对应的BaseCRUDVM,并初始化 if (currentvmname.ToLower().Contains("apibatchvm")) { vmtype = this.GetType().Assembly.GetExportedTypes().Where(x => x.IsSubclassOf(typeof(BaseCRUDVM)) && x.Name.ToLower().Contains("apivm") == true).FirstOrDefault(); } else { vmtype = this.GetType().Assembly.GetExportedTypes().Where(x => x.IsSubclassOf(typeof(BaseCRUDVM)) && x.Name.ToLower().Contains("apivm") == false).FirstOrDefault(); } IBaseCRUDVM vm = null; if (vmtype != null) { vm = vmtype.GetConstructor(System.Type.EmptyTypes).Invoke(null) as IBaseCRUDVM; vm.CopyContext(this); } var entityList = DC.Set().CheckIDs(idsData).ToList(); //循环所有数据 for (int i = 0; i < entityList.Count; i++) { try { //如果找不到对应数据,则输出错误 TModel entity = entityList[i]; if (vm != null) { vm.SetEntity(entity); } if (entity == null) { ErrorMessage.Add(idsData[i], CoreProgram._localizer?["Sys.DataNotExist"]); rv = false; break; } //如果能找到,则循环LinkedVM中的属性,给entity中同名属性赋值 foreach (var pro in pros) { var proToSet = entity.GetType().GetSingleProperty(pro.Name); var val = FC.ContainsKey("LinkedVM." + pro.Name) ? FC["LinkedVM." + pro.Name] : null; if(val == null && FC.ContainsKey("LinkedVM." + pro.Name + "[]")) { val = FC["LinkedVM." + pro.Name + "[]"]; } var valuetoset = pro.GetValue(LinkedVM); if (proToSet != null && val != null && valuetoset != null) { var hasvalue = true; if ( val is StringValues sv && StringValues.IsNullOrEmpty(sv) == true) { hasvalue = false; } if (hasvalue) { proToSet.SetValue(entity, valuetoset); } } } //调用controller方法验证model //try //{ // Controller.GetType().GetMethod("RedoValidation").Invoke(Controller, new object[] { entity }); //} //catch { } //如果有对应的BaseCRUDVM则使用其进行数据验证 if (vm != null) { vm.Validate(); var errors = vm.MSD; if (errors != null && errors.Count > 0) { var error = ""; foreach (var key in errors.Keys) { if (errors[key].Count > 0) { error += errors[key].Select(x => x.ErrorMessage).ToSepratedString(); } } if (error != "") { ErrorMessage.Add(idsData[i], error); rv = false; break; } } } if (typeof(IBasePoco).IsAssignableFrom( typeof(TModel))) { IBasePoco ent = entity as IBasePoco; if (ent.UpdateTime == null) { ent.UpdateTime = DateTime.Now; } if (string.IsNullOrEmpty(ent.UpdateBy)) { ent.UpdateBy = LoginUserInfo?.ITCode; } } DC.UpdateEntity(entity); } catch (Exception e) { SetExceptionMessage(e, idsData[i]); rv = false; } } //进行数据库的修改操作 if (rv == true) { try { DC.SaveChanges(); } catch (Exception e) { SetExceptionMessage(e, null); rv = false; } } //如果有错误,输出错误信息 if (rv == false) { if (ErrorMessage.Count > 0) { foreach (var id in idsData) { if (!ErrorMessage.ContainsKey(id)) { ErrorMessage.Add(id, CoreProgram._localizer?["Sys.Rollback"]); } } } RefreshErrorList(); } return rv; } protected void RefreshErrorList() { ListVM.DoSearch(); foreach (var item in ListVM.GetEntityList()) { item.BatchError = ErrorMessage.Where(x => x.Key == item.GetID().ToString()).Select(x => x.Value).FirstOrDefault(); } } } }