using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Data; using System.Data.Common; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text.Json.Serialization; using System.Text.RegularExpressions; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using MySqlConnector; using Npgsql; using NpgsqlTypes; using NPOI.HSSF.Util; using NPOI.SS.UserModel; using NPOI.SS.Util; using NPOI.XSSF.UserModel; using WalkingTec.Mvvm.Core.Extensions; namespace WalkingTec.Mvvm.Core { public delegate object ColumnFormatCallBack(T entity, object fieldValue) where T : TopBasePoco; /// /// ListVM的搜索模式枚举 /// public enum ListVMSearchModeEnum { Search, //搜索 Export, //导出 Batch, //批量 Selector,//选择器 MasterDetail, // CheckExport, Custom1, Custom2, Custom3, Custom4, Custom5 }; /// /// ListVM的基类,所有ListVM应该继承这个类, 基类提供了搜索,导出等列表常用功能 /// /// ListVM中的Model类 /// ListVM使用的Searcher类 public class BasePagedListVM : BaseVM, IBasePagedListVM where TModel : TopBasePoco where TSearcher : BaseSearcher { [JsonIgnore] public string TotalText { get; set; } = CoreProgram._localizer?["Sys.Total"]; public virtual DbCommand GetSearchCommand() { return null; } private int? _childrenDepth; /// /// 多级表头深度 默认 1级 /// public int GetChildrenDepth() { if (_childrenDepth == null) { _childrenDepth = _getHeaderDepth(); } return _childrenDepth.Value; } /// /// GridHeaders /// [JsonIgnore] private IEnumerable> GridHeaders { get; set; } /// /// GetHeaders /// /// public IEnumerable> GetHeaders() { if (GridHeaders == null) { GridHeaders = InitGridHeader(); } return GridHeaders; } /// /// 计算多级表头深度 /// /// private int _getHeaderDepth() { IEnumerable> headers = GetHeaders(); return headers.Max(x => x.MaxDepth); } private List _gridActions; /// /// 页面动作 /// public List GetGridActions() { if (_gridActions == null) { _gridActions = InitGridAction(); } return _gridActions; } /// /// 初始化 InitGridHeader,继承的类应该重载这个函数来设定数据的列和动作 /// protected virtual IEnumerable> InitGridHeader() { return new List>(); } protected virtual List InitGridAction() { return new List(); } #region GenerateExcel /// /// 生成Excel /// /// 生成的Excel文件 public virtual byte[] GenerateExcel() { NeedPage = false; //获取导出的表头 if (GridHeaders == null) { GetHeaders(); } //去掉ID列和Action列 RemoveActionAndIdColumn(); //如果没有数据源,进行查询 if (IsSearched == false) { DoSearch(); } //获取分成Excel的个数 ExportMaxCount = ExportMaxCount == 0 ? 1000000 : (ExportMaxCount > 1000000 ? 1000000 : ExportMaxCount); ExportExcelCount = EntityList.Count < ExportMaxCount ? 1 : ((EntityList.Count % ExportMaxCount) == 0 ? (EntityList.Count / ExportMaxCount) : (EntityList.Count / ExportMaxCount + 1)); //如果是1,直接下载Excel,如果是多个,下载ZIP包 if (ExportExcelCount == 1) { return DownLoadExcel(); } else { return DownLoadZipPackage(typeof(TModel).Name + "_" + DateTime.Now.ToString("yyyyMMddHHmmssffff")); } } /// /// 根据集合生成单个Excel /// /// /// private IWorkbook GenerateWorkBook(List List) { IWorkbook book = new XSSFWorkbook(); ISheet sheet = book.CreateSheet(); IRow row = sheet.CreateRow(0); //创建表头样式 ICellStyle headerStyle = book.CreateCellStyle(); headerStyle.FillBackgroundColor = ExportTitleBackColor == null ? HSSFColor.LightBlue.Index : ExportTitleBackColor.Value; headerStyle.FillPattern = FillPattern.SolidForeground; headerStyle.FillForegroundColor = ExportTitleBackColor == null ? HSSFColor.LightBlue.Index : ExportTitleBackColor.Value; headerStyle.BorderBottom = BorderStyle.Thin; headerStyle.BorderTop = BorderStyle.Thin; headerStyle.BorderLeft = BorderStyle.Thin; headerStyle.BorderRight = BorderStyle.Thin; IFont font = book.CreateFont(); font.FontName = "Calibri"; font.FontHeightInPoints = 12; font.Color = ExportTitleFontColor == null ? HSSFColor.Black.Index : ExportTitleFontColor.Value; headerStyle.SetFont(font); ICellStyle cellStyle = book.CreateCellStyle(); cellStyle.BorderBottom = BorderStyle.Thin; cellStyle.BorderTop = BorderStyle.Thin; cellStyle.BorderLeft = BorderStyle.Thin; cellStyle.BorderRight = BorderStyle.Thin; //生成表头 int max = MakeExcelHeader(sheet, GridHeaders, 0, 0, headerStyle); //放入数据 var ColIndex = 0; for (int i = 0; i < List.Count; i++) { ColIndex = 0; var DR = sheet.CreateRow(i + max); foreach (var baseCol in GridHeaders) { foreach (var col in baseCol.BottomChildren) { //处理枚举变量的多语言 bool IsEmunBoolParp = false; var proType = col.FieldType; if (proType.IsEnumOrNullableEnum()) { IsEmunBoolParp = true; } //获取数据,并过滤特殊字符 string text = Regex.Replace(col.GetText(List[i]).ToString(), @"<[^>]*>", String.Empty); //处理枚举变量的多语言 if (IsEmunBoolParp) { string enumdisplay = PropertyHelper.GetEnumDisplayName(proType, text); if (string.IsNullOrEmpty(enumdisplay) == false) { text = enumdisplay; } else { if (int.TryParse(text, out int enumvalue)) { text = PropertyHelper.GetEnumDisplayName(proType, enumvalue); } } } //建立excel单元格 ICell cell; if (col.FieldType?.IsNumber() == true) { cell = DR.CreateCell(ColIndex, CellType.Numeric); try { cell.SetCellValue(Convert.ToDouble(text)); } catch { } } else { cell = DR.CreateCell(ColIndex); cell.SetCellValue(text); } cell.CellStyle = cellStyle; ColIndex++; } } } return book; } private byte[] DownLoadExcel() { var book = GenerateWorkBook(EntityList); byte[] rv = new byte[] { }; using (MemoryStream ms = new MemoryStream()) { book.Write(ms); rv = ms.ToArray(); } return rv; } private byte[] DownLoadZipPackage(string FileName) { //文件根目录 string RootPath = $"{Directory.GetCurrentDirectory()}\\{FileName}"; //文件夹目录 string FilePath = $"{RootPath}//FileFolder"; //压缩包目录 string ZipPath = $"{RootPath}//{FileName}.zip"; //打开文件夹 DirectoryInfo FileFolder = new DirectoryInfo(FilePath); if (!FileFolder.Exists) { //创建文件夹 FileFolder.Create(); } else { //清空文件夹 FileSystemInfo[] Files = FileFolder.GetFileSystemInfos(); foreach (var item in Files) { if (item is DirectoryInfo) { DirectoryInfo Directory = new DirectoryInfo(item.FullName); Directory.Delete(true); } else { File.Delete(item.FullName); } } } //放入数据 for (int i = 0; i < ExportExcelCount; i++) { var List = EntityList.Skip(i * ExportMaxCount).Take(ExportMaxCount).ToList(); var WorkBook = GenerateWorkBook(List); string SavePath = $"{FilePath}/{FileName}_{i + 1}.xlsx"; using (FileStream FS = new FileStream(SavePath, FileMode.CreateNew)) { WorkBook.Write(FS); } } //生成压缩包 ZipFile.CreateFromDirectory(FilePath, ZipPath); //读取压缩包 FileStream ZipFS = new FileStream(ZipPath, FileMode.Open, FileAccess.Read); byte[] bt = new byte[ZipFS.Length]; ZipFS.Read(bt, 0, bt.Length); ZipFS.Close(); //删除根目录文件夹 DirectoryInfo RootFolder = new DirectoryInfo(RootPath); if (RootFolder.Exists) { RootFolder.Delete(true); } return bt; } /// /// 生成Excel的表头 /// /// /// /// /// /// /// private int MakeExcelHeader(ISheet sheet, IEnumerable> cols, int rowIndex, int colIndex, ICellStyle style) { var row = sheet.GetRow(rowIndex); if (row == null) { row = sheet.CreateRow(rowIndex); } int maxLevel = cols.Select(x => x.MaxLevel).Max(); //循环所有列 foreach (var col in cols) { //添加新单元格 var cell = row.CreateCell(colIndex); cell.CellStyle = style; cell.SetCellValue(col.Title); var bcount = col.BottomChildren.Count(); var rowspan = 0; if (rowIndex >= 0) { rowspan = maxLevel - col.MaxLevel; } var cellRangeAddress = new CellRangeAddress(rowIndex, rowIndex + rowspan, colIndex, colIndex + bcount - 1); sheet.AddMergedRegion(cellRangeAddress); if (rowspan > 0 || bcount > 1) { cell.CellStyle.Alignment = HorizontalAlignment.Center; cell.CellStyle.VerticalAlignment = VerticalAlignment.Center; } for (int i = cellRangeAddress.FirstRow; i <= cellRangeAddress.LastRow; i++) { IRow r = CellUtil.GetRow(i, sheet); for (int j = cellRangeAddress.FirstColumn; j <= cellRangeAddress.LastColumn; j++) { ICell c = CellUtil.GetCell(r, (short)j); c.CellStyle = style; } } if (col.Children != null && col.Children.Count() > 0) { MakeExcelHeader(sheet, col.Children, rowIndex + rowspan + 1, colIndex, style); } colIndex += bcount; } return maxLevel; } #endregion #region Old public SortInfo CreateSortInfo(Expression> pro, SortDir dir) { SortInfo rv = new SortInfo { Property = PropertyHelper.GetPropertyName(pro), Direction = dir }; return rv; } /// /// InitList后触发的事件 /// public event Action> OnAfterInitList; /// ///记录批量操作时列表中选择的Id /// public List Ids { get; set; } public string SelectorValueField { get; set; } /// /// 是否已经搜索过 /// [JsonIgnore] public bool IsSearched { get; set; } [JsonIgnore] public bool PassSearch { get; set; } /// /// 查询模式 /// [JsonIgnore] public ListVMSearchModeEnum SearcherMode { get; set; } /// /// 是否需要分页 /// [JsonIgnore] public bool NeedPage { get; set; } /// /// 允许导出Excel的最大行数,超过行数会分成多个文件,最多不能超过100万 /// [JsonIgnore] public int ExportMaxCount { get; set; } /// /// 根据允许导出的Excel最大行数,算出最终导出的Excel个数 /// [JsonIgnore] public int ExportExcelCount { get; set; } /// /// 导出文件第一行背景颜色,使用HSSFColor,例如:HSSFColor.Red.Index /// [JsonIgnore] public short? ExportTitleBackColor { get; set; } /// /// 导出文件第一行文字颜色,使用HSSFColor,例如:HSSFColor.Red.Index /// [JsonIgnore] public short? ExportTitleFontColor { get; set; } /// /// 数据列表 /// [JsonIgnore] public List EntityList { get; set; } /// /// 搜索条件 /// [JsonIgnore] public TSearcher Searcher { get; set; } /// /// 使用 VM 的 Id 来生成 SearcherDiv 的 Id /// [JsonIgnore] public string SearcherDivId { get { return this.UniqueId + "Searcher"; } } /// /// 替换查询条件,如果被赋值,则列表会使用里面的Lambda来替换原有Query里面的Where条件 /// [JsonIgnore()] public Expression ReplaceWhere { get; set; } /// /// 构造函数 /// public BasePagedListVM() { //默认需要分页 NeedPage = true; //初始化数据列表 EntityList = new List(); //初始化搜索条件 Searcher = typeof(TSearcher).GetConstructor(Type.EmptyTypes).Invoke(null) as TSearcher; } /// /// 获取数据列表 /// /// 数据列表 public IEnumerable GetEntityList() { if (IsSearched == false && (EntityList == null || EntityList.Count == 0)) { DoSearch(); } return EntityList?.AsEnumerable(); } /// /// 调用InitListVM并触发OnAfterInitList事件 /// public void DoInitListVM() { InitListVM(); OnAfterInitList?.Invoke(this); } /// /// 初始化ListVM,继承的类应该重载这个函数来设定数据的列和动作 /// protected virtual void InitListVM() { } public virtual bool GetIsSelected(object item) { return false; } public override void Validate() { Searcher?.Validate(); base.Validate(); } /// /// 设定行前景色,继承的类应重载这个函数来根据每行的数据显示不同的前景色 /// /// 数据 /// 前景颜色 public virtual string SetFullRowColor(object entity) { return ""; } /// /// 设定行背景色,继承的类应重载这个函数来根据每行的数据显示不同的背景色 /// /// 数据 /// 背景颜色 public virtual string SetFullRowBgColor(object entity) { return ""; } /// /// 设定搜索语句,继承的类应该重载这个函数来指定自己的搜索语句 /// /// 搜索语句 public virtual IOrderedQueryable GetSearchQuery() { return DC.Set().OrderByDescending(x => x.ID); } /// /// 设定导出时搜索语句,继承的类应该重载这个函数来指定自己导出时的搜索语句,如不指定则默认和搜索用的搜索语句相同 /// /// 搜索语句 public virtual IOrderedQueryable GetExportQuery() { return GetSearchQuery(); } /// /// 设定搜索语句,继承的类应该重载这个函数来指定自己导出时的搜索语句,如不指定则默认和搜索用的搜索语句相同 /// /// 搜索语句 public virtual IOrderedQueryable GetSelectorQuery() { return GetSearchQuery(); } /// /// 设定勾选后导出的搜索语句,继承的类应该重载这个函数来指定自己导出时的搜索语句,如不指定则默认和搜索用的搜索语句相同 /// /// 搜索语句 public virtual IOrderedQueryable GetCheckedExportQuery() { var baseQuery = GetBatchQuery(); return baseQuery; } /// /// 设定批量模式下的搜索语句,继承的类应重载这个函数来指定自己批量模式的搜索语句,如果不指定则默认使用Ids.Contains(x.Id)来代替搜索语句中的Where条件 /// /// 搜索语句 public virtual IOrderedQueryable GetBatchQuery() { var baseQuery = GetSearchQuery(); if (ReplaceWhere == null) { var mod = new WhereReplaceModifier(Ids.GetContainIdExpression()); var newExp = mod.Modify(baseQuery.Expression); var newQuery = baseQuery.Provider.CreateQuery(newExp) as IOrderedQueryable; return newQuery; } else { return baseQuery; } } /// /// 设定主从模式的搜索语句,继承的类应该重载这个函数来指定自己主从模式的搜索语句,如不指定则默认和搜索用的搜索语句相同 /// /// 搜索语句 public virtual IOrderedQueryable GetMasterDetailsQuery() { return GetSearchQuery(); } /// /// 进行搜索 /// public virtual void DoSearch() { var cmd = GetSearchCommand(); if (cmd == null) { IOrderedQueryable query = null; //根据搜索模式调用不同的函数 switch (SearcherMode) { case ListVMSearchModeEnum.Search: query = GetSearchQuery(); break; case ListVMSearchModeEnum.Export: query = GetExportQuery(); break; case ListVMSearchModeEnum.Batch: query = GetBatchQuery(); break; case ListVMSearchModeEnum.MasterDetail: query = GetMasterDetailsQuery(); break; case ListVMSearchModeEnum.CheckExport: query = GetCheckedExportQuery(); break; case ListVMSearchModeEnum.Selector: query = GetSelectorQuery(); break; default: query = GetSearchQuery(); break; } //如果设定了替换条件,则使用替换条件替换Query中的Where语句 if (ReplaceWhere != null) { var mod = new WhereReplaceModifier(ReplaceWhere as Expression>); var newExp = mod.Modify(query.Expression); query = query.Provider.CreateQuery(newExp) as IOrderedQueryable; } if (Searcher.SortInfo != null) { var mod = new OrderReplaceModifier(Searcher.SortInfo); var newExp = mod.Modify(query.Expression); query = query.Provider.CreateQuery(newExp) as IOrderedQueryable; } if (typeof(IPersistPoco).IsAssignableFrom( typeof(TModel))) { var mod = new IsValidModifier(); var newExp = mod.Modify(query.Expression); query = query.Provider.CreateQuery(newExp) as IOrderedQueryable; } if (PassSearch == false) { //如果需要分页,则添加分页语句 if (NeedPage && Searcher.Limit != -1) { //获取返回数据的数量 var count = query.Count(); if (count < 0) { count = 0; } if (Searcher.Limit == 0) { Searcher.Limit = ConfigInfo?.UIOptions.DataTable.RPP ?? 20; } //根据返回数据的数量,以及预先设定的每页行数来设定数据量和总页数 Searcher.Count = count; Searcher.PageCount = (int)Math.Ceiling((1.0 * Searcher.Count / Searcher.Limit)); if (Searcher.Page <= 0) { Searcher.Page = 1; } if (Searcher.PageCount > 0 && Searcher.Page > Searcher.PageCount) { Searcher.Page = Searcher.PageCount; } EntityList = query.Skip((Searcher.Page - 1) * Searcher.Limit).Take(Searcher.Limit).AsNoTracking().ToList(); } else //如果不需要分页则直接获取数据 { EntityList = query.AsNoTracking().ToList(); Searcher.Count = EntityList.Count(); Searcher.Limit = EntityList.Count(); Searcher.PageCount = 1; Searcher.Page = 1; } } else { EntityList = query.AsNoTracking().ToList(); } } else { ProcessCommand(cmd); } IsSearched = true; //调用AfterDoSearch函数来处理自定义的后续操作 AfterDoSearcher(); } private void ProcessCommand(DbCommand cmd) { object total; if (Searcher.Page <= 0) { Searcher.Page = 1; } if (DC.Database.IsMySql()) { List parms = new List(); foreach (MySqlParameter item in cmd.Parameters) { parms.Add(new MySqlParameter(string.Format("@{0}", item.ParameterName), item.Value)); } if (cmd.CommandType == CommandType.StoredProcedure) { parms.Add(new MySqlParameter("@SearchMode", Enum.GetName(typeof(ListVMSearchModeEnum), SearcherMode))); parms.Add(new MySqlParameter("@NeedPage", (NeedPage && Searcher.Limit != -1))); parms.Add(new MySqlParameter("@CurrentPage", Searcher.Page)); parms.Add(new MySqlParameter("@RecordsPerPage", Searcher.Limit)); parms.Add(new MySqlParameter("@Sort", Searcher.SortInfo?.Property)); parms.Add(new MySqlParameter("@SortDir", Searcher.SortInfo?.Direction)); parms.Add(new MySqlParameter("@IDs", Ids == null ? "" : Ids.ToSepratedString())); MySqlParameter outp = new MySqlParameter("@TotalRecords", MySqlDbType.Int64) { Value = 0, Direction = ParameterDirection.Output }; parms.Add(outp); } var pa = parms.ToArray(); EntityList = DC.Run(cmd.CommandText, cmd.CommandType, pa).ToList(); if (cmd.CommandType == CommandType.StoredProcedure) { total = pa.Last().Value; } else { total = EntityList.Count; } } else if (DC.Database.IsNpgsql()) { List parms = new List(); foreach (NpgsqlParameter item in cmd.Parameters) { parms.Add(new NpgsqlParameter(string.Format("@{0}", item.ParameterName), item.Value)); } if (cmd.CommandType == CommandType.StoredProcedure) { parms.Add(new NpgsqlParameter("@SearchMode", Enum.GetName(typeof(ListVMSearchModeEnum), SearcherMode))); parms.Add(new NpgsqlParameter("@NeedPage", (NeedPage && Searcher.Limit != -1))); parms.Add(new NpgsqlParameter("@CurrentPage", Searcher.Page)); parms.Add(new NpgsqlParameter("@RecordsPerPage", Searcher.Limit)); parms.Add(new NpgsqlParameter("@Sort", Searcher.SortInfo?.Property)); parms.Add(new NpgsqlParameter("@SortDir", Searcher.SortInfo?.Direction)); parms.Add(new NpgsqlParameter("@IDs", Ids == null ? "" : Ids.ToSepratedString())); NpgsqlParameter outp = new NpgsqlParameter("@TotalRecords", NpgsqlDbType.Bigint) { Value = 0, Direction = ParameterDirection.Output }; parms.Add(outp); } var pa = parms.ToArray(); EntityList = DC.Run(cmd.CommandText, cmd.CommandType, pa).ToList(); if (cmd.CommandType == CommandType.StoredProcedure) { total = pa.Last().Value; } else { total = EntityList.Count; } } else { List parms = new List(); foreach (SqlParameter item in cmd.Parameters) { parms.Add(new SqlParameter(string.Format("@{0}", item.ParameterName), item.Value)); } if (cmd.CommandType == CommandType.StoredProcedure) { parms.Add(new SqlParameter("@SearchMode", Enum.GetName(typeof(ListVMSearchModeEnum), SearcherMode))); parms.Add(new SqlParameter("@NeedPage", (NeedPage && Searcher.Limit != -1))); parms.Add(new SqlParameter("@CurrentPage", Searcher.Page)); parms.Add(new SqlParameter("@RecordsPerPage", Searcher.Limit)); parms.Add(new SqlParameter("@Sort", Searcher.SortInfo?.Property)); parms.Add(new SqlParameter("@SortDir", Searcher.SortInfo?.Direction)); parms.Add(new SqlParameter("@IDs", Ids == null ? "" : Ids.ToSepratedString())); SqlParameter outp = new SqlParameter("@TotalRecords", 0) { Direction = ParameterDirection.Output }; parms.Add(outp); } var pa = parms.ToArray(); EntityList = DC.Run(cmd.CommandText, cmd.CommandType, pa).ToList(); if (cmd.CommandType == CommandType.StoredProcedure) { total = pa.Last().Value; } else { total = EntityList.Count; } } if (NeedPage && Searcher.Limit != -1) { if (total != null) { try { Searcher.Count = long.Parse(total.ToString()); Searcher.PageCount = (int)((Searcher.Count - 1) / Searcher.Limit + 1); } catch { } } } else { Searcher.PageCount = EntityList.Count; } } public DateTime AddTime(DateTime dt, string type, int size) { switch (type) { case "year": return dt.AddYears(size); case "month": return dt.AddMonths(size); case "day": return dt.AddDays(size); case "hour": return dt.AddHours(size); case "minute": return dt.AddMinutes(size); case "second": return dt.AddSeconds(size); default: return dt; } } /// /// 搜索后运行的函数,继承的类如果需要在搜索结束后进行其他操作,可重载这个函数 /// public virtual void AfterDoSearcher() { if (SearcherMode == ListVMSearchModeEnum.Selector && Ids != null && Ids.Count > 0 && EntityList != null && EntityList.Count > 0) { foreach (var item in EntityList) { if (string.IsNullOrEmpty(SelectorValueField) || SelectorValueField.ToLower() == "id") { var id = item.GetID(); if (Ids.Contains(id.ToString())) { item.Checked = true; } } else { var v = item.GetPropertyValue(SelectorValueField); if (Ids.Contains(v.ToString())) { item.Checked = true; } } } } } /// /// 删除所有ActionGridColumn的列 /// public void RemoveActionColumn(object root = null) { if (root == null) { if (GridHeaders == null) { GetHeaders(); } root = GridHeaders; } if (root != null) { //IEnumerable> var aroot = root as List>; var toRemove = aroot.Where(x => x.ColumnType == GridColumnTypeEnum.Action).FirstOrDefault(); aroot.Remove(toRemove); foreach (var child in aroot) { if (child.Children != null && child.Children.Count() > 0) { RemoveActionColumn(child.Children); } } } } public void RemoveAction() { _gridActions = new List(); } public void RemoveActionAndIdColumn(IEnumerable> root = null) { if (root == null) { if (GridHeaders == null) { GetHeaders(); } root = GridHeaders; } if (root != null) { var aroot = root as List>; List> remove = null; var idpro = typeof(TModel).GetSingleProperty("ID")?.PropertyType; if (idpro == typeof(string)) { remove = aroot.Where(x => x.ColumnType == GridColumnTypeEnum.Action || x.Hide == true || x.DisableExport).ToList(); } else { remove = aroot.Where(x => x.ColumnType == GridColumnTypeEnum.Action || x.Hide == true || x.DisableExport || x.FieldName?.ToLower() == "id").ToList(); } foreach (var item in remove) { aroot.Remove(item); } foreach (var child in root) { if (child.Children != null && child.Children.Count() > 0) { RemoveActionAndIdColumn(child.Children); } } } } /// /// 添加Error列,主要为批量模式使用 /// public void AddErrorColumn() { GetHeaders(); //寻找所有Header为错误信息的列,如果没有则添加 if (GridHeaders.Where(x => x.Field == "BatchError").FirstOrDefault() == null) { var temp = GridHeaders as List>; if (temp.Where(x => x.ColumnType == GridColumnTypeEnum.Action).FirstOrDefault() == null) { temp.Add(this.MakeGridColumn(x => x.BatchError, Width: 200, Header: Core.CoreProgram._localizer?["Sys.Error"]).SetForeGroundFunc(x => "ff0000").SetFixed(GridColumnFixedEnum.Right)); } else { temp.Insert(temp.Count - 1, this.MakeGridColumn(x => x.BatchError, Width: 200, Header: Core.CoreProgram._localizer?["Sys.Error"]).SetForeGroundFunc(x => "ff0000").SetFixed(GridColumnFixedEnum.Right)); } } } public void ProcessListError(List Entities) { if(Entities == null) { return; } EntityList = Entities; IsSearched = true; bool haserror = false; List keys = new List(); if (string.IsNullOrEmpty(DetailGridPrix) == false) { if (EntityList.Any(x => x.BatchError != null)) { haserror = true; } else { foreach (var item in MSD.Keys) { if (item.StartsWith(DetailGridPrix+"[")) { var errors = MSD[item]; if (errors.Count > 0) { Regex r = new Regex($"{DetailGridPrix}\\[(.*?)\\]"); try { if (int.TryParse(r.Match(item).Groups[1].Value, out int index)) { EntityList[index].BatchError = errors.Select(x => x.ErrorMessage).ToSepratedString(); keys.Add(item); haserror = true; } } catch { } } } } foreach (var item in keys) { MSD.RemoveModelError(item); } } if (haserror) { AddErrorColumn(); } } } public TModel CreateEmptyEntity() { return typeof(TModel).GetConstructor(Type.EmptyTypes).Invoke(null) as TModel; } public void ClearEntityList() { EntityList?.Clear(); } public string DetailGridPrix { get; set; } public Type ModelType => typeof(TModel); #endregion public virtual void UpdateEntityList(bool updateAllFields = false) { if (EntityList != null) { var ftype = EntityList.GetType().GenericTypeArguments.First(); var itemPros = ftype.GetAllProperties(); foreach (var newitem in EntityList) { var subtype = newitem.GetType(); if (typeof(IBasePoco).IsAssignableFrom( subtype)) { IBasePoco ent = newitem as IBasePoco; if (ent.UpdateTime == null) { ent.UpdateTime = DateTime.Now; } if (string.IsNullOrEmpty(ent.UpdateBy)) { ent.UpdateBy = LoginUserInfo?.ITCode; } } //循环页面传过来的子表数据,将关联到TopBasePoco的字段设为null,并且把外键字段的值设定为主表ID foreach (var itempro in itemPros) { if (itempro.PropertyType.IsSubclassOf(typeof(TopBasePoco))) { itempro.SetValue(newitem, null); } } } IEnumerable data = null; //打开新的数据库联接,获取数据库中的主表和子表数据 using (var ndc = DC.CreateNew()) { var ids = EntityList.Select(x => x.GetID().ToString()).ToList(); data = ndc.Set().AsNoTracking().Where(ids.GetContainIdExpression()).ToList(); } //比较子表原数据和新数据的区别 IEnumerable toadd = null; IEnumerable toremove = null; Utils.CheckDifference(data, EntityList, out toremove, out toadd); //设定子表应该更新的字段 List setnames = new List(); foreach (var field in FC.Keys) { if (field.StartsWith("EntityList[0].")) { string name = field.Replace("EntityList[0].", ""); setnames.Add(name); } } //前台传过来的数据 foreach (var newitem in EntityList) { //数据库中的数据 foreach (var item in data) { //需要更新的数据 if (newitem.GetID().ToString() == item.GetID().ToString()) { dynamic i = newitem; var newitemType = item.GetType(); foreach (var itempro in itemPros) { if (!itempro.PropertyType.IsSubclassOf(typeof(TopBasePoco)) && (updateAllFields == true || setnames.Contains(itempro.Name))) { var notmapped = itempro.GetCustomAttribute(); if (itempro.Name != "ID" && notmapped == null && itempro.PropertyType.IsList() == false) { DC.UpdateProperty(i, itempro.Name); } } } if ( typeof(IBasePoco).IsAssignableFrom( item.GetType())) { DC.UpdateProperty(i, "UpdateTime"); DC.UpdateProperty(i, "UpdateBy"); } } } } //需要删除的数据 foreach (var item in toremove) { //如果是PersistPoco,则把IsValid设为false,并不进行物理删除 if (typeof(IPersistPoco).IsAssignableFrom( ftype)) { (item as IPersistPoco).IsValid = false; if (typeof(IBasePoco).IsAssignableFrom(ftype)) { (item as IBasePoco).UpdateTime = DateTime.Now; (item as IBasePoco).UpdateBy = LoginUserInfo?.ITCode; } dynamic i = item; DC.UpdateEntity(i); } else { foreach (var itempro in itemPros) { if (itempro.PropertyType.IsSubclassOf(typeof(TopBasePoco))) { itempro.SetValue(item, null); } } dynamic i = item; DC.DeleteEntity(i); } } //需要添加的数据 foreach (var item in toadd) { if (typeof(IBasePoco).IsAssignableFrom( item.GetType())) { IBasePoco ent = item as IBasePoco; if (ent.CreateTime == null) { ent.CreateTime = DateTime.Now; } if (string.IsNullOrEmpty(ent.CreateBy)) { ent.CreateBy = LoginUserInfo?.ITCode; } } DC.AddEntity(item); } DC.SaveChanges(); } } } }