zoukankan      html  css  js  c++  java
  • Mego(04)

    前言

    相信做过信息系统的朋友都会遇到EXCEL导入导出的相关开发,做过不少EXCEL导入导出后总结起来大致有如下几种方式实现:

    • ADO.NET的OldDb或ODBC连接EXCEL使用DataTable来读取数据。
    • Microsoft.Office.Interop.Excel用微软提供的组件操作WorkSheet对象。
    • 使用一些第三方的库比如Fast Excel、ExcelDataReader等等。

    今天要向大家介绍的更简单的方式来实现日常开发的各种EXCEL导入导出需求。

    简单导入

    我们还是使用ADO.NET中的System.Data.OleDb做为底层,这种方式会很高效。先定义一个对象用来承载数据。

    public class Product
    {
        public int Id { get; set; }
        public string Code { get; set; }
        public string Name { get; set; }
        public int Category { get; set; }
        public bool IsValid { get; set; }
    }
    

    声明一个连接字符串模型如下

    private const string conStr =
        @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 12.0 Xml;HDR=YES'";
    

    最后声明一个访问EXCEL的上下文

    public class ExcelContext : DbContext
    {
        public ExcelContext(string filename)
            : base(string.Format(conStr, filename), "System.Data.OleDb.Excel")
        {
            this.Configuration.EnableAutoConversionStorageTypes = true;
        }
        public DbSet<Product> Products { get; set; }
    }
    

    到这里准备工作就完成了,然后我们就能从数据源提取数据如下所示:

    using (var context = new ExcelContext("sample.xls"))
    {
        var data = context.Products.ToArray();
    }
    

    只要两行代码就能获取数据转成NET的对象,如果这里有一个能访问业务数据库的上下文就能直接导入数据,例如下面的临时代码:

    using (var context = new OracleContext())
    {
        context.Products.AddRange(data);
        context.Executor.Execute();
    }
    

    到此我们都以一个很简单的方式就能完成从EXCEL提取并向数据库导入数据的工作。

    万能导入

    也许你会考虑到导入EXCEL的格式会很多,不能每次都来定义一个上下文和数据对象类,这里我们可以定义一种通用方式来读取EXCEL。
    我们还是利用上面的连接字符串再定义一个通用的数据上下文。

    public class AnonymouExcelContext : DbContext
    {
        public AnonymouExcelContext(string filename)
            : base(string.Format(conStr, filename), "System.Data.OleDb.Excel")
        {
            this.Configuration.EnableAutoConversionStorageTypes = true;
        }
    }
    

    接着我们利用C#的匿名对象来读取数据。

    using (var context = new ExcelContext("sample.xls"))
    {
        var item = new { Id = 1, Name = "P", IsValid = false };
        var data = context.Set(item, "Products").Where(a => a.Id > 20).ToArray();
    }
    

    我们先定义一个匿名对象,其实就是以匿名形式声明了将要导入数据的字段,使用匿名类型还一个好处就是可以进行LINQ操作,例如上面的代码。

    导出数据

    导出EXCEL也是个比较麻烦的事,首先你需要写表头,然后再写入数据,可能在不同的场景下你需要重要写导出的代码这个在使用Microsoft.Office.Interop.Excel导出时特别严重。这里我们还是用上面的数据上下文来导出数据。
    首先我们先创建一些数据用于导出。

    Random r = new Random();
    var products = Enumerable.Range(0, 1000).Select(i => new Product()
    {
        Id = i,
        Name = "Product " + i.ToString(),
        Category = r.Next(1, 10),
        Code = "P" + i.ToString(),
        IsValid = true
    });
    

    我们需要创建一个空白的EXCEL文件,这里不声明代码了。
    最后就是写入表头和内容:

    using (var context = new ExcelContext(filename))
    {
        var operate = context.Database.Manager.CreateTable<Product>();
        context.Executor.Execute(operate);//创建表头
        context.Products.AddRange(products);
        context.Executor.Execute();//写入数据
    }
    

    同样的匿名对象也是同样可以如此操作,
    创建数据

    Random r = new Random();
    var items = Enumerable.Range(0, 1000).Select(i => new
    {
        Id = i,
        Name = "Product " + i.ToString(),
        Category = r.Next(1, 10),
        IsValid = true
    }).ToArray();
    

    写入数据

    using (var context = new ExcelContext(filename))
    {
        var item = items[0];
        var operate = context.Database.Manager.CreateTable(item.GetType(),
            DbName.NameOnly("Sheet1$"));
        context.Executor.Execute(operate);
        context.Set(item, "[Sheet1$]").AddRange(items);
        context.Executor.Execute();
    }
    

    复杂EXCEL导入

    通过上面的代码已经可以满足大多数的开发需求,不过业务需求永远无止境,不知道下面EXCEL导入案例大家是否有遇到。
    客户需要一次导入上万条订单加明细数据,在正式导入到数据库之前还要在系统界面上浏览确认及修改,确认无误后才发命令写入到数据库。(最麻烦的是这是个基于WEB的系统)。

    上传EXCEL是少不了的,但是浏览修改会麻烦一点,不过基于良好的用户体验需要把EXCEL保存在服务器的临时位置,然后分页向用户显示数据并提供修改功能,最后当用户确认后才提交到数据库。
    首先我们先创建一个相对复杂的数据上下文。

    internal class ComplexContext : DbContext
    {
        public ComplexContext(string filename)
            : base(string.Format(conStr, filename), "System.Data.OleDb.Excel")
        {
            this.Configuration.EnableAutoConversionStorageTypes = true;
        }
        public DbSet<Order> Orders { get; set; }
        public DbSet<OrderDetail> OrderDetails { get; set; }
        public DbSet<Customer> Customers { get; set; }
        public DbSet<Product> Products { get; set; }
    }
    

    这里忽略数据类的定义,这里的数据间关系是订单有多个明细,订单关系一个客户,明细关系一个产品,对于EXCEL而言这已经很复杂了。
    不过在这里你可以很容易的查询所有订单及订单明细,过滤加分页向用户显示数据,如下所示

    using (var context = new ComplexContext("sample.xls"))
    {
        var query = from a in context.Orders.Include(a=>a.Details)
                    where a.Id > 4
                    select a;
        var items = query.Take(10).Skip(20).ToArray();
    }
    

    我们直接上个图来证明下数据的正确性。

    以上代码都已上传Github

    以上都是基于Mego框架实现的对EXCEL操作,当然Mego还支持许多数据库,欢迎大家试用。

    声明:一个新的技术或框架出现后还是需要时间的沉淀,我个人觉的至少需要半年以上的时间,所以请暂时不要将该框架应用到你觉的重要的系统中。不过也请大家可以多多试用,帮助Mego可以快速成长,感谢各位的问题及意见反馈。
  • 相关阅读:
    spring-ioc
    Hibernate之二级缓存
    hibernate之HQL语句
    hibernate 多对多关联关系
    hibernate关联关系(一对多)
    Hibernate之主键生成策略
    struts2的CRUD
    struts2的OGNL
    struts2的初步认识
    Maven介绍
  • 原文地址:https://www.cnblogs.com/CarefreeXT/p/8988264.html
Copyright © 2011-2022 走看看