讀取Excel的好工具 LinqToExcel

數個月前使用者在詢問能不能匯出excel,於是上網找了資料後,便刻了匯出excel功能給他們,沒想到這只是噩夢的開始,幾周前又開始問我能不能用匯入的...

於是就找到了這個套件,讓我們一起來看看怎麼使用它吧

 

用之前先做個介紹

相關連結:

1.官方網站

2.讀取 Excel 你還在用 NPOI 嗎?快來試試 LinqToExcel

3.LINQ - 實作 LinqToExcel

另外附上問題的解法

1.提供者並未登錄於本機電腦上 - 下載Microsoft Access Database Engine並進行安裝

(注意電腦位元數)

2.第一次上傳時總是沒反應:

請在讀取前加入這行程式碼

excelFile.DatabaseEngine = LinqToExcel.Domain.DatabaseEngine.Ace;

進入正題啦~

首先先去nuget將套件載回來,並在要使用的地方using

using LinqToExcel;

 

建立物件並給與excel的實體路徑

ExcelQueryFactory excelFile = new ExcelQueryFactory(filePath);

 

設定只做讀取以及資料庫引擎

excelFile.DatabaseEngine = LinqToExcel.Domain.DatabaseEngine.Ace;
excelFile.ReadOnly = true;

欄位繫節的部分直接在要存的類之中掛attr

例如excel欄位名稱為編號,轉入程式之中的命名要為ID,直接在類中掛

[ExcelColumn(欄位名稱)]即可,如下

需要特別處理的是列舉的型別對應部分,需要自己手動自幹

//第一種寫法 excel欄位 繫節到 class中的屬性
excelFile.AddMapping<UploadExcel>(UploadExcel => UploadExcel.StatusID, "狀態");

//第二種寫法 excel欄位是列舉型別,透過Func來型別對應
//這個方法是在第三個參數中,把每一列的編號(第二個參數)傳進來做處理,並綁定到第一個參數ID
//這個範例是 將數字轉型為列舉(Status) 的處理方式 
excelFile.AddMapping<UploadExcel>(UploadExcel => UploadExcel.StatusID, "狀態", p => (Status)Convert.ToInt32(p));

 

在實務面上還會遇到一個問題,就是列舉在變數命名時,通常會命名為英文,但轉送到client端的時候必須顯示中文,因此會再加掛attr,例如這樣。

再匯入的時候問題就來了,使用者不會知道要輸入10或是OnLine,而只會輸入「上線」,因此又產生了新的問題。

這邊再透過先前介紹的第二個方法稍微衍伸做個處理,即可把資料再轉型回來

首先 讓列舉顯示Description的資料可以參考這篇 列舉型別的資料對應

public static class ExtenxionMethod
{
    public static string ExtGetAttributeDescription(this Enum en)
    {
        Type type = en.GetType();
        MemberInfo[] members = type.GetMember(en.ToString());

        // 如果沒有任何attribute則報錯
        if (members == null)
            throw new ArgumentException("There is no property in this attribute");

        object[] attributes = members[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

        // 如果attribute中沒有description則報錯
        if (attributes == null)
            throw new ArgumentException("There is no attribute in this description");

        return ((DescriptionAttribute)attributes[0]).Description;
    }
}

再來透過迴圈把所有列舉的名稱以及其Description資料讀出來,並存入字典中

        public static Dictionary<string, string> ToDictionary<T>() where T : struct, IConvertible
        {
            Type type = typeof(T);
            if (!type.IsEnum)
                throw new ArgumentException("Type must be an enum");

            Dictionary<string, string> di = new Dictionary<string, string>();
            foreach (string str in Enum.GetNames(type))
                // 這段的ExtGetAttributeDescription()是前面寫的擴充方法
                di.Add(str, ((T)Enum.Parse(type, str, true) as Enum).ExtGetAttributeDescription());

            return di;
        }

此時已經取到列舉的字典,當然如果要取int+Description,也可以透過這段程式碼修改來達到目的

最後再AddMapping前先取得字典

Dictionary<string, string> di = ToDictionary<Status>();

再來就是列舉資料對應的程式碼了

            excelFile.AddMapping<UploadExcel>(
                // 對應的DTO欄位
                UploadExcel=> UploadExcel.StatusID,
                // Excel對應的欄位
                "狀態",
                // 將列舉型別轉型的Lambda函式
                p =>
                    (Status)Enum.Parse(
                        typeof(Status),
                        di.Where(w => w.Value.Equals(p)).First().Key,
                        true));

這樣就可以讓使用者輸入的資料與列舉型別進行對應囉!

 

最後事實證明,使用者的慾望是永無止盡的,後來我又被要求做了其他的excel的功能...


LINE討論群FB討論區

歡迎您的加入,讓這個社群更加美好!

聯絡方式:
FaceBook
E-Mail