使用 EPPlus 封装的 excel 表格导入功能 (二) delegate 委托 --永远滴神
前言
接上一篇 使用 EPPlus 封装的 excel 表格导入功能 (一)
前一篇的是大概能用但是不一定好用的版本
后来我又重新封装扩展了一下
支持自定义更多东西(但是封装地是否有必要我就说不清了)
上个版本的问题
上个版本封装之后的使用代码:
public ICollection<TestDto> ExcelImport(IFormFile file){ var config = ExcelCellOption<TestDto> .GenExcelOption("姓名", item => item.Name) .Add("年龄", item => item.Age, item => int.Parse(item)) .Add("性别", item => item.Gender, item => item == "男") .Add("身高", item => item.Height, item => double.Parse(item)); ICollection<TestDto> result = ExcelOperation.ExcelToEntity(file.OpenReadStream(), config); return result;}
设计逻辑是 一个单元格 对应 实体中的一个字段
这个设计一开始是没什么问题的,将excel中的数据导入到 DTO集合 中,然后就可以进行下一步的操作
但在实际使用的时候发现,拿到 DTO集合 之后,总是需要再套个 foreach
做一些初始化操作
比如:
- 通过身份证号码判断性别
- 通过用户名查询账单信息
- 给某个字段赋值
- 对应导入的数据生成其他的数据
- ......
基于以上的需要,重新修改后的调用代码如下:
public ICollection<TestDto> ExcelImport(IFormFile file){ var config = new ExcelImportOption<TestDto>() .Add("姓名", item => item.Name) .Add("年龄", item => item.Age, item => int.Parse(item)) .Default(item => item.Height, 233) .AddInit(item => { item.Name += "hhhhhhhh"; item.Gender = false; return item; }); ICollection<TestDto> result = ExcelOperation.ExcelToEntity(file.OpenReadStream(), config); return result;}
代码/设计/想法
由于我想在解析 excel 的同时进行初始化操作,所以委托这东西必不可少
Func<T, T> Init { get; set; }
由于现阶段的需求比较简单,不需要什么复杂的参数,所以使用 Func<>
或 Action<>
都可以
定义这个初始化 Init
之后,单纯的 ICollection<ExcelCellOption<T>>
已经是不够用了
所以重新定义了一个 配置
public class ExcelOption<T>{ public ICollection<ExcelCellOption<T>> FieldOption { get; set; } = new List<ExcelCellOption<T>>(); public ICollection<ExcelCellOption<T>> DefaultOption { get; set; } = new List<ExcelCellOption<T>>(); public Func<T, T> Init { get; set; }}
其中的 DefaultOption
没有也行
然后对 ExcelOption<T>
进行扩展
public static class ExcelOptionExt{ ...... public static ExcelOption<T> AddInit<T>(this ExcelOption<T> origin, Func<T, T> action = null) { if (origin.Init == null) origin.Init = action; return origin; } // 没有 DefaultOption 的情况下使用 FieldOption 也行 public static ExcelOption<T> Default<T, E>(this ExcelOption<T> origin, Expression<Func<T, E>> prop, object defaultValue = null) { var member = prop.GetMember(); if (origin.DefaultOption == null) origin.DefaultOption = new List<ExcelCellOption<T>>(); origin.DefaultOption.Add(new ExcelCellOption<T> { PropName = member.Name, Prop = (PropertyInfo)member, ExcelField = string.Empty, Action = item => defaultValue }); return origin; } ......}
配置 接口改变之后,ExcelOperation
的 ExcelToEntity
方法也要进行修改
public static ICollection<T> ExcelToEntity<T>(Stream excelStream, ExcelOption<T> options){ using ExcelPackage pack = new ExcelPackage(excelStream); // 合并 FieldOption 和 DefaultOption var propOptions = options.FieldOption.Concat(options.DefaultOption); var sheet = pack.Workbook.Worksheets[1]; int rowCount = sheet.Dimension.Rows, colCount = sheet.Dimension.Columns; // 获取对应设置的 表头 以及其 column var header = sheet.Cells[1, 1, 1, sheet.Dimension.Columns] .Where(item => propOptions.Any(opt => opt.ExcelField == item.Value?.ToString().Trim())) .ToDictionary(item => item.Value?.ToString().Trim(), item => item.End.Column); List<T> data = new List<T>(); // 将excel 的数据转换为 对应实体 for (int r = 2; r <= rowCount; r++) { // 将单行数据转换为 表头:数据 的键值对 var rowData = sheet.Cells[r, 1, r, colCount] .Where(item => header.Any(title => title.Value == item.End.Column)) .Select(item => new KeyValuePair<string, string>(header.First(title => title.Value == item.End.Column).Key, item.Value?.ToString().Trim())) .ToDictionary(item => item.Key, item => item.Value); var obj = Activator.CreateInstance(typeof(T)); // 根据对应传入的设置 为obj赋值 foreach (var option in propOptions) { if (!string.IsNullOrEmpty(option.ExcelField)) { var value = rowData.ContainsKey(option.ExcelField) ? rowData[option.ExcelField] : string.Empty; if (!string.IsNullOrEmpty(value)) option.Prop.SetValue(obj, option.Action == null ? value : option.Action(value)); } else option.Prop.SetValue(obj, option.Action == null ? null : option.Action(string.Empty)); } // 实际上只是加了个 Init 操作 if (options.Init != null) obj = options.Init((T)obj); data.Add((T)obj); } return data;}
然后这个阶段就算是大功告成了!
再贴一次使用时的代码
public ICollection<TestDto> ExcelImport(IFormFile file){ var config = new ExcelImportOption<TestDto>() .Add("姓名", item => item.Name) .Add("年龄", item => item.Age, item => int.Parse(item)) .Default(item => item.Height, 233) .AddInit(item => { item.Name += "hhhhhhhh"; item.Gender = false; return item; }); ICollection<TestDto> result = ExcelOperation.ExcelToEntity(file.OpenReadStream(), config); return result;}
完整代码
public class ExcelOperation{ public static ICollection<T> ExcelToEntity<T>(Stream excelStream, ExcelOption<T> options) { using ExcelPackage pack = new ExcelPackage(excelStream); // 合并 FieldOption 和 DefaultOption var propOptions = options.FieldOption.Concat(options.DefaultOption); var sheet = pack.Workbook.Worksheets[1]; int rowCount = sheet.Dimension.Rows, colCount = sheet.Dimension.Columns; // 获取对应设置的 表头 以及其 column var header = sheet.Cells[1, 1, 1, sheet.Dimension.Columns] .Where(item => propOptions.Any(opt => opt.ExcelField == item.Value?.ToString().Trim())) .ToDictionary(item => item.Value?.ToString().Trim(), item => item.End.Column); List<T> data = new List<T>(); // 将excel 的数据转换为 对应实体 for (int r = 2; r <= rowCount; r++) { // 将单行数据转换为 表头:数据 的键值对 var rowData = sheet.Cells[r, 1, r, colCount] .Where(item => header.Any(title => title.Value == item.End.Column)) .Select(item => new KeyValuePair<string, string>(header.First(title => title.Value == item.End.Column).Key, item.Value?.ToString().Trim())) .ToDictionary(item => item.Key, item => item.Value); var obj = Activator.CreateInstance(typeof(T)); // 根据对应传入的设置 为obj赋值 foreach (var option in propOptions) { if (!string.IsNullOrEmpty(option.ExcelField)) { var value = rowData.ContainsKey(option.ExcelField) ? rowData[option.ExcelField] : string.Empty; if (!string.IsNullOrEmpty(value)) option.Prop.SetValue(obj, option.Action == null ? value : option.Action(value)); } else option.Prop.SetValue(obj, option.Action == null ? null : option.Action(string.Empty)); } if (options.Init != null) obj = options.Init((T)obj); data.Add((T)obj); } return data; } /// <summary> /// 将表格数据转换为指定的数据实体 /// </summary> public static ICollection<T> ExcelToEntity<T>(Stream excelStream, ICollection<ExcelCellOption<T>> options) { using ExcelPackage pack = new ExcelPackage(excelStream); var sheet = pack.Workbook.Worksheets[1]; int rowCount = sheet.Dimension.Rows, colCount = sheet.Dimension.Columns; // 获取对应设置的 表头 以及其 column var header = sheet.Cells[1, 1, 1, sheet.Dimension.Columns] .Where(item => options.Any(opt => opt.ExcelField == item.Value?.ToString().Trim())) .ToDictionary(item => item.Value?.ToString().Trim(), item => item.End.Column); List<T> data = new List<T>(); // 将excel 的数据转换为 对应实体 for (int r = 2; r <= rowCount; r++) { // 将单行数据转换为 表头:数据 的键值对 var rowData = sheet.Cells[r, 1, r, colCount] .Where(item => header.Any(title => title.Value == item.End.Column)) .Select(item => new KeyValuePair<string, string>(header.First(title => title.Value == item.End.Column).Key, item.Value?.ToString().Trim())) .ToDictionary(item => item.Key, item => item.Value); var obj = Activator.CreateInstance(typeof(T)); // 根据对应传入的设置 为obj赋值 foreach (var option in options) { if (!string.IsNullOrEmpty(option.ExcelField)) { var value = rowData.ContainsKey(option.ExcelField) ? rowData[option.ExcelField] : string.Empty; if (!string.IsNullOrEmpty(value)) option.Prop.SetValue(obj, option.Action == null ? value : option.Action(value)); } else option.Prop.SetValue(obj, option.Action == null ? null : option.Action(string.Empty)); } data.Add((T)obj); } return data; }}public class ExcelOption<T>{ public ICollection<ExcelCellOption<T>> FieldOption { get; set; } = new List<ExcelCellOption<T>>(); public ICollection<ExcelCellOption<T>> DefaultOption { get; set; } = new List<ExcelCellOption<T>>(); public Func<T, T> Init { get; set; }}public class ExcelCellOption<T>{ /// <summary> /// 对应excel中的header字段 /// </summary> public string ExcelField { get; set; } /// <summary> /// 对应字段的属性(实际上包含PropName) /// </summary> public PropertyInfo Prop { get; set; } /// <summary> /// 就是一个看起来比较方便的标识 /// </summary> public string PropName { get; set; } /// <summary> /// 转换 表格 数据的方法 (现在是个鸡肋了) /// </summary> public Func<string, object> Action { get; set; } public static ICollection<ExcelCellOption<T>> GenExcelOption<E>(string field, Expression<Func<T, E>> prop, Func<string, object> action = null) { var member = prop.GetMember(); return new List<ExcelCellOption<T>>{ new ExcelCellOption<T> { PropName = member.Name, Prop = (PropertyInfo)member, ExcelField = field, Action = action } }; }}public static class ExcelOptionExt{ public static ICollection<ExcelCellOption<T>> Add<T, E>(this ICollection<ExcelCellOption<T>> origin, string field, Expression<Func<T, E>> prop, Func<string, object> action = null) { var member = prop.GetMember(); origin.Add(new ExcelCellOption<T> { PropName = member.Name, Prop = (PropertyInfo)member, ExcelField = field, Action = action }); return origin; } public static ExcelOption<T> Add<T, E>(this ExcelOption<T> origin, string field, Expression<Func<T, E>> prop, Func<string, object> action = null) { var member = prop.GetMember(); if (origin.FieldOption == null) origin.FieldOption = new List<ExcelCellOption<T>>(); origin.FieldOption.Add(new ExcelCellOption<T> { PropName = member.Name, Prop = (PropertyInfo)member, ExcelField = field, Action = action }); return origin; } public static ExcelOption<T> Default<T, E>(this ExcelOption<T> origin, Expression<Func<T, E>> prop, object defaultValue = null) { var member = prop.GetMember(); if (origin.DefaultOption == null) origin.DefaultOption = new List<ExcelCellOption<T>>(); origin.DefaultOption.Add(new ExcelCellOption<T> { PropName = member.Name, Prop = (PropertyInfo)member, ExcelField = string.Empty, Action = item => defaultValue }); return origin; } public static ExcelOption<T> AddInit<T>(this ExcelOption<T> origin, Func<T, T> action = null) { if (origin.Init == null) origin.Init = action; return origin; }}
未完待续
原文转载:http://www.shaoqun.com/a/698743.html
e淘网:https://www.ikjzd.com/w/1698
关键词分析工具:https://www.ikjzd.com/w/1968
使用EPPlus封装的excel表格导入功能(二)delegate委托--永远滴神前言接上一篇使用EPPlus封装的excel表格导入功能(一)前一篇的是大概能用但是不一定好用的版本后来我又重新封装扩展了一下支持自定义更多东西(但是封装地是否有必要我就说不清了)上个版本的问题上个版本封装之后的使用代码:publicICollection<TestDto>ExcelImport(IFor
孙琦:https://www.ikjzd.com/w/1638
imgur:https://www.ikjzd.com/w/156
外贸圈:https://www.ikjzd.com/w/1083
扛老师那雪白的两条玉腿 巨大在她腿间进进出出:http://www.30bags.com/m/a/249915.html
口述:同居3年 我惨不忍睹:http://lady.shaoqun.com/m/a/114475.html
如何搭建一个高效的亚马逊运营团队:https://www.ikjzd.com/home/14575
没有评论:
发表评论