1. 程式人生 > >Mego(04) - NET簡單實現EXCEL導入導出

Mego(04) - NET簡單實現EXCEL導入導出

過濾 創建表 imp ade ffice 顯示 容易 業務需求 false

前言

相信做過信息系統的朋友都會遇到EXCEL導入導出的相關開發,做過不少EXCEL導入導出後總結起來大致有如下幾種方式實現:

  • ADO.NET的OldDb或ODBC連接EXCEL使用DataTable來讀取數據。
  • Microsoft.Office.Interop.Excel用微軟提供的組件操作WorkSheet對象。
  • 使用一些第三方的庫比如Fast Excel、ExcelDataReader等等。

今天要向大家介紹的更簡單的方式來實現日常開發的各種EXCEL導入導出需求。

簡單導入

我們還是使用ADO.NET中的System.Data.OleDb做為底層,這種方式會很高效。先定義一個對象用來承載數據。
c# 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; } }

c#
然後聲明一個連接字符串模型如下

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(04) - NET簡單實現EXCEL導入導出