[Excel][Solution] 簡單使用LinqToExcel讀取Excel檔案資料

簡單使用LinqToExcel讀取Excel檔案資料

前言

 

在專案開發時,常會面臨到使用者希望保有操作Excel文件習慣來同步系統資料,因此有Excel上傳及讀取需求產生;筆者實務上大多透過強大的NPOI來完成所有操作Excel的任務,但當需求就只需讀取Excel資料時,是不是可以使用更簡易的方式來完成呢? 沒錯殺雞是不需要用到牛刀的,我們可以使用LinqToExcel來簡化讀取Excel的工作,並且自動mapping到相對應類別物件中以便後續資料的操作。以下介紹。

 

 

安裝LinqToExcel

 

NuGet中LinqToExcel預設是32-bit ( x86 ) 版本,若伺服器是 64-bit 則需使用64位元版本,否則若將32-bit版本佈署到預設以 64-bit 執行的 IIS 站台時,會有「無法載入檔案或組件」問題發生;筆者有切身之痛所以要特別說明一下,至於細節可參考保哥 如何解決 LinqToExcel 發生「無法載入檔案或組件」問題 文章。

 

image

 

要在NuGet中找到64位元版本的LinqToExcel時,需要輸入LinqToExcel_x64才可被搜尋到喔

 

image

 

 

環境問題排除

 

如果操作Microsoft Office Excel 2007 (.xlsx ) 以上版本時,發生「'Microsoft.ACE.OLEDB.12.0' 提供者並未登錄於本機電腦上」錯誤訊息,請服用 2007 Office system 驅動程式:資料連線元件來排除此問題。

 

image

 

 

實作介紹

 

以下筆者將使用LinqPad來進行實作。主要針對既定格式之Excel進行資料的讀取,而實作會以2種不同的Excel格式進行測試,希望有興趣的朋友可藉由以下範例了解LinqToExcel讀取資料的控制細節。

 

 

簡易表格

 

主要就是在訂貨清單表單中,僅放置"一個"表格來列出訂購資訊。

 

image

 

面對這種簡單的表格,首先我們可以先定義Order類別來mapping到表格中各訂購資訊欄位。而LinqToExcel操作方式相當簡單,首先就是透過ExcelQueryFactory載入指定Excel檔案,接著直接使用Worksheet撈出訂貨清單表單中的表格,並且將資料mapping到Order類別中。 示意圖如下所示。

 

image

 

完整測試代碼如下

 


void Main()
{
	// Load excel file
	var excel = new ExcelQueryFactory(@"D:\Sample.xlsx");
		
	// Query
	var orders = from x in excel.Worksheet<Order>("訂貨清單") 
						where x.OrderId != null
						select x;
	// Show Data
	orders.Dump();
}

public class Order
{
	public string OrderId {get;set;}
	public string ProductName {get;set;}
	public int Amount {get;set;}
	public double Price {get;set;}
}

 

最後成功地從Excel撈出所有orders資料

 

image

 

 

複雜表格

 

在使用者清單表單中,包括一個獨立資料(Date)及下方使用者表格。在LinqToExcel可以指定讀取的範圍,因此要順利取得下方表格資料不會有太大的困難;至於上方獨立資料(Date)則可以利用Excel中"定義名稱"功能來標記該資料位置,方便讓LinqToExcel透過此定義名稱獲得該資料內容。

 

image

 

在Excel中使用"定義名稱"功能相當簡單,只要在該Cell上按下滑鼠右鍵,在選單中點選"定義名稱"

 

image

 

接著就可以輸入此定義功能的名稱及範圍,而LinqToExcel就可使用此名稱來取得對應資料。

 

image

 

按下 Ctrl + F3 後可顯示名稱管理員,可確認剛剛加入的新名稱是否列於其中。

 

image

 

 

使用LinqToExcel面對稍微複雜的Excel格式時,取值技巧約略以下三點:

 

   1. 可使用 NamedRangeNoHeader 來依據Excel"定義功能"中所設定"名稱"進行取值。

 

   2. 面對Excel欄位名稱與類別屬性名稱不一致時,可透過AddMapping來建立映射關聯。

 

   3. 可使用 WorksheetRange 來指定表單範圍(左上位置為B4,右下位置則為E0,其中0表示無筆數下限)

 

image

 

完整測試代碼如下


void Main()
{
	// Load excel file
	var excel = new ExcelQueryFactory(@"D:\Sample.xlsx");
	
	// Query by Range Name
	var createDate = from x in excel.NamedRangeNoHeader("CreateDate")
				     select x[0].Cast<DateTime>();
	
	// Mapping class's property to column name
	excel.AddMapping<User>( u=>u.UserId, "User ID");
						
	// Query by Sheet Name
	var users = from x in excel.WorksheetRange<User>("B4","E0","使用者清單") 
				where x.UserId != null
				select x;			
				
	createDate.Dump();
	users.Dump();
}


public class User
{
	//[ExcelColumn("User ID")]
	public string UserId {get;set;}
	public string Name {get;set;}
	public DateTime Birthday {get;set;}
	public int Height {get;set;}
}

 

最後成功地從Excel所撈出createDate及users資料

 

image

 

 

參考資訊

 

https://github.com/paulyoder/LinqToExcel


希望此篇文章可以幫助到需要的人

若內容有誤或有其他建議請不吝留言給筆者喔 !