Mego(04) - NET簡單實現EXCEL導入導出
前言
相信做過信息系統的朋友都會遇到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; } }
然後聲明一個連接字符串模型如下
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導入導出