c#使用EPPlus封装excel表格导入功能的问题

前言

最近做系统的时候有很多 excel导入 的功能,以前我前后端都做的时候是在前端解析,然后再做个批量插入的接口

我觉着这样挺好的,后端部分可以做的很简单(很偷懒的)

但是因为各种各样的原因,最终还是需要做个专门的 excel导入 接口

遇到的问题

由于之前从来没有在后端部分处理过表格,所以我选择看一下同事的代码是怎么写的

虽然我之前没写过相关的业务,但是直觉的认为这样写非常麻烦,那个 ExcelHelper 好像也没干什么事,我希望一套操作下来可以把 excel 转成能够直接传入 AddRange 进行批量新增的实体集合

所以我就决定自己封装。

结果展示(略)

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;
}

最终可以直接生成"初始化"数据的 result

代码/设计/想法

我希望使用的时候通过传入 表格字段数据实体.属性 的关系集合

实现解析表格的同时生成对应的 实体对象

然后我对上述 关系 的定义如下

public class ExcelCellOption<T>
{
    /// <summary>
    /// 对应excel中的header表头(title)
    /// </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; }
}

之后给他加了个静态方法 GenExcelOption<E> 生成关系集合 ICollection<ExcelCellOption<T>>

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
        }
    };
}

为了方便之后加新的配置项

给返回类型 ICollection<ExcelCellOption<T>> 搞个扩展方法 Add

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;
    }
}

使用的时候就可以根据excel表格生成对应的 关系集合 (配置)

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));

有了配置之后需要根据配置解析excel生成数据实体了

写了个方法如下

public class ExcelOperation
{
    /// <summary>
    /// 将表格数据转换为指定的数据实体
    /// </summary>
    public static ICollection<T> ExcelToEntity<T>(Stream excelStream, ICollection<ExcelCellOption<T>> options)
    {
        using ExcelPackage pack = new(excelStream);
        var sheet = pack.Workbook.Worksheets[1];
        int rowCount = sheet.Dimension.Rows, colCount = sheet.Dimension.Columns;
        // 获取对应设置的 表头 以及其 column下标
        var header = sheet.Cells[1, 1, 1, colCount ]
        .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();
        // 将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));
                }
                // 可以用来初始化与表格无关的字段 如 创建时间 Guid主键 之类的东西
                else
                    option.Prop.SetValue(obj, option.Action == null ? null : option.Action(string.Empty));
            }
            data.Add((T)obj);
        }
        return data;
    }
}

最终调用

ExcelOperation.ExcelToEntity(file.OpenReadStream(), config)

传入文件流和配置集合即可

完整代码

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using AutoMapper.Internal;
using OfficeOpenXml;

namespace XXX.XXX.XXX.XXX
{
    public class ExcelOperation
    {
        /// <summary>
        /// 将表格数据转换为指定的数据实体
        /// </summary>
        public static ICollection<T> ExcelToEntity<T>(Stream excelStream, ICollection<ExcelCellOption<T>> options)
        {
            using ExcelPackage pack = new(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()))
            .ToDictionary(item => item.Value.ToString(), item => item.End.Column);
            List<T> data = new();
            // 将excel 的数据转换为 对应实体F
            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()))
                .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));
                    }
                    // 可以用来初始化与表格无关的字段 如 创建时间 Guid主键 之类的东西
                    else
                        option.Prop.SetValue(obj, option.Action == null ? null : option.Action(string.Empty));
                }
                data.Add((T)obj);
            }
            return data;
        }
    }

    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 ExcelOptionAdd
    {
        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;
        }
    }
}

其实这已经是旧版本了

新的版本过几天大概会发

到此这篇关于c#使用EPPlus封装excel表格导入功能的问题的文章就介绍到这了,更多相关c#使用EPPlus封装excel表格导入内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C#实现Excel导入sqlite的方法

    本文实例讲述了C#实现Excel导入sqlite的方法,是非常实用的技巧.分享给大家供大家参考.具体方法如下: 首先需要引用system.date.sqlite 具体实现代码如下: system.date.sqlite system.date.sqlite.linq //导入--Excel导入sqlite private void button2_Click(object sender, EventArgs e) { DAL.Sqlite da = new DAL.Sqlite("DataByE

  • 让C# Excel导入导出 支持不同版本Office

    问题:最近在项目中遇到,不同客户机安装不同Office版本,在导出Excel时,发生错误. 找不到Excel Com组件,错误信息如下.  未能加载文件或程序集"Microsoft.Office.Interop.Excel, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"或它的某一个依赖项.系统找不到指定的文件. 解决方法: 1.引用高版本的的Excel.dll组件,最新版本14.0.0 防止客户安

  • C#导入导出Excel数据的两种方法

    本文为大家分享了C#导入导出Excel数据的具体代码,供大家参考,具体内容如下 注:对于实体类对象最好新建一个并且继承原有实体类,这样可以将类型进行修改: 方法一:此种方法是用EPPLUS中的FileInfo流进行读取的(是不是流我还真不太了解,若有懂得请留言,非常感谢了) using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tas

  • C#的Excel导入、导出

    本篇主要介绍C#的Excel导入.导出,供大家参考,具体内容如下 一. 介绍 1.1 第三方类库:NPOI 说明:NPOI是POI项目的.NET 版本,可用于Excel.Word的读写操作. 优点:不用装Office环境. 下载地址:http://npoi.codeplex.com/releases 1.2 Excel结构介绍 工作簿(Workbook):每个Excel文件可理解为一个工作簿. 工作表(Sheet):一个工作簿(Workbook)可以包含多个工作表. 行(row):一个工作表(S

  • C#导入导出EXCEL文件的代码实例

    复制代码 代码如下: using System;using System.Data;using System.Data.OleDb; namespace ZFSoft.Joint{    public class ExcelIO    {        private int _ReturnStatus;        private string _ReturnMessage; /// <summary>        /// 执行返回状态        /// </summary&g

  • c#将Excel数据导入到数据库的实现代码

    假如Excel中的数据如下: 数据库建表如下: 其中Id为自增字段: 代码: 复制代码 代码如下: using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.UI;using System.Web.UI.WebControls;using System.Data;using System.Data.OleDb;using System.Configuratio

  • c#使用EPPlus封装excel表格导入功能的问题

    前言 最近做系统的时候有很多 excel导入 的功能,以前我前后端都做的时候是在前端解析,然后再做个批量插入的接口 我觉着这样挺好的,后端部分可以做的很简单(很偷懒的) 但是因为各种各样的原因,最终还是需要做个专门的 excel导入 接口 遇到的问题 由于之前从来没有在后端部分处理过表格,所以我选择看一下同事的代码是怎么写的 虽然我之前没写过相关的业务,但是直觉的认为这样写非常麻烦,那个 ExcelHelper 好像也没干什么事,我希望一套操作下来可以把 excel 转成能够直接传入 AddRa

  • Python处理EXCEL表格导入操作分步讲解

    目录 一.前期准备 二.编写代码基本思路 三.编写代码读取数据 四.结语 一.前期准备 此篇使用两种导入excel数据的方式,形式上有差别,但两者的根本方法实际上是一样的. 首先需要安装两个模块,一个是pandas,另一个是xlrd. 在顶部菜单栏中点击文件,再点击设置,然后在设置中找到以下界面,并点击“+”号. 然后会出现以下界面,在搜索框中分别搜索以上两个模块:pandas/xlrd. 选中搜索出来的模块,并点击左下角的的安装按钮,便可将模块安装到自己电脑中. 需要注意的是,xlrd的新版本

  • SpringBoot整合EasyExcel实现Excel表格导出功能

    目录 栗子 1.组件介绍 2.配置文件 SpringBoot项目pom.xml 3.项目代码 项目结构 ExportController.java Mock.java CitySheet.java CompanySheet.java UserSheet.java SpringBootEasyexcelApplication.java 4.效果展示 单个sheet导出 多个sheet导出 5.总结 栗子 在后端管理系统的开发中,经常有需要导出当前表格数据的功能,有些前端表格组件可以直接做到,但是不

  • jQuery仿Excel表格编辑功能的实现代码

    在 Excel 中可进行的操作,你几乎都可以在网页中做到,如拖动复制.Ctrl+C .Ctrl+V 等等. 另外在浏览器支持方面,它支持以下的浏览器 IE7+, FF, Chrome, Safari, Opera. 如何使用:     首先在页面中引入 jQuery 框架和 Handsontable 插件的相关 JS 和 CSS 文件,以下列出的两个是必要的,还有其它的是可选的,如果需要某个功能时就(参看demo)加上. 复制代码 代码如下: <script src="jquery.min

  • 如何将excel表格数据导入postgresql数据库

    实际的工作中,我们经常会碰到统计数据的工作,有些维度的统计数据因为工作需要我们需要导出为excel作为报表附件供不同的部门审查.为了方便以后的对比工作,领导会让在数据库中创建一张表,用于专门记录这些数据.此时我们DBA需要将这些excel表格导入到数据库中,copy和\copy命令为我们提供了解决办法,本文主要通过copy命令的使用,介绍如何将excel表格导入至数据库中.关于copy及\copy命令的区别,请广大博友通过另一篇文章<如何将postgresql数据库表内数据导出为excel格式>

  • Django上传excel表格并将数据写入数据库的详细步骤

    目录 前言: 一.上传文件: 二.解析 excel 导入数据库 前言: 最近公司领导要统计技术部门在各个业务条线花费的工时百分比,而 jira 当前的 Tempo 插件只能统计个人工时.于是就写了个报表工具,将 jira 中导出的个人工时excel表格 导入数据库,在后端处理各个业务工时占比.后来研究了 jira 的 API 文档 ,放弃了之前的思路,直接调用 jira API 处理数据 ,这个先不谈.这篇博客主要介绍 Django 上传文件,然后解析 excel 导入数据库. 一.上传文件:

  • vue导入处理Excel表格功能步骤详解

    目录 1. 前言 2.vue导入Excel表格 2.1 使用ElementUI中的upload组件 2.2 使用input文件上传 3. 总体代码与效果 4. 总结 1. 前言 最近遇到前端导入并处理excel表格的情况,趁此机会刚好研究一下vue导入并处理excel数据:当然自己手撸一个工具没有那么多时间,本文只是借助现有的工具来做一下工具使用总结. 2.vue导入Excel表格 vue导入Excel表格主要有两种常用的方法,一个是借助ElementUI文件上传进行表格导入,另一个是自带的in

  • Vue实现导出excel表格功能

    引言: 最近使用vue在做一个后台系统,技术栈 vue + iView ,在页面中生成表格后, iView可以实现表格的导出,不过只能导出csv格式的,并不适合项目需求. 如果想要导出Excel 在src目录下创建一个文件(vendor)进入 Blob.js 和 Export2Excel.js npm install -S file-saver 用来生成文件的web应用程序 npm install -S xlsx 电子表格格式的解析器 npm install -D script-loader 将

  • java实现批量导入Excel表格数据到数据库

    本文是基于Apache poi类实现的批量导入读取Excel文件,所以要先引入Apache poi的依赖 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.1</version> </dependency> <dependency> <groupId>org.a

  • 使用python对excel表格处理的一些小功能

    python对excel表格处理的一些小功能 功能概览pandas库的一些应用文件读入计算表格中每一行的英文单词数简单用textblob进行自然语言情感分析判断一行中是不是有两列值都与其他行重复(可推广至多列)对表格中的两列自定义函数运算判断表格中某列中是否有空对表格某列中时间格式的修正运用matplotlib画时间序列图,重叠图 功能概览 做数模模拟赛时学到的一些对表格处理的知识,为了方便自己以后查找,遂写成一篇文章,也希望能帮助大家:) pandas库的一些应用 文件读入 代码如下,每一句后

随机推荐