[C#][SQL Server] 在Console利用Entity Framework將Excel、Word匯入至資料庫

  • 1147
  • 0
  • 2018-01-09

在Console上使用Entity Framework將Excel及Word匯入至資料庫

用Visual Studio 2017做的,使用LINQ開發速度快很多很多很多!

1.首先,當然是建立Console專案...
檔案 => 新增 =>專案/方案 => 主控台應用程式 => 先命名「MyConsole」

2.利用NuGet加入Entity Framework套件至專案參考
工具 => NuGet封裝管理員 => 管理方案的NuGet套件 => 選「EntityFramework」

3.加入Microsoft Excel及Word的參考
專案 => 加入參考 => COM => 「Microsoft Word 12.0 Object Library」、「Microsoft Excel 12.0 Object Library」

4.加入Database模型
方案總管建立一個名為「Model」的資料夾 => 右鍵加入參考 => 新增項目 => Visual C# 項目 => 資料 => 選擇「ADO.NET」 => 命名「EntityDB」
ps. 連接完成後會自動將Database資訊加入App.config

5.寫程式看是匯入Word還是Excel

6.處理完的檔案成功的話就直接刪除,失敗的話移到特定資料夾

程式參考如下:

標頭

using System.Data.Entity;
using System.IO;
using Excel = Microsoft.Office.Interop.Excel;
using Word = Microsoft.Office.Interop.Word;
using MyConsole.Model; //連接Database的東東都在「Model」箱子唷,要記得加上!

資料夾構造樹狀分支Word、Excel
\\ServerName\e$\FileFolder\1.Word\xxxxxxxx.docx
\\ServerName\e$\FileFolder\2.Excel\xxxxxxxx.xlsx

主程式

static void Main(string[] args)
{
    //連接EntityFramework DB
    EntityDB db = new EntityDB();

    //根路徑
    string FilePathRoot = @"\\server\e$\FileFolder";

    //事件名稱
    string Event = null;

    //跑迴圈抓根路徑底下資料夾的路徑
    foreach(string EventsPath in Directory.GetDirectories(FilePathRoot))
    {
        //擷取資料夾名稱,分辨檔案類別
        Event = EventsPath.Split('.').Last();
		
        if (Event == "Word")
        {
            Word匯入(EventsPath);
        }
        if (Event == "Excel")
        {
            Excel匯入(EventsPath);
        }
    }
}

匯入Word:

static public void Word匯入(string EventsPath, string Event)
{
    //連接Entity Framework
    EntityDB db = new EntityDB();

    //開啟Word應用程式
    Word.Application wordApp = new Word.Application
    {
        DisplayAlerts = Word.WdAlertLevel.wdAlertsNone,	//關閉警告
        Visible = false,				//背景執行
    };

    //讀取資料夾檔案,但排除開啟時產生的"~$"開頭的隱藏暫存檔
    foreach(string MemberPath in Directory.GetFiles(EventsPath, @"*.*").Where(x => !x.Contains("~")))
    {
        //開啟路徑檔案
        Word.Document wordDoc = wordApp.Documents.Open(MemberPath, ReadOnly:true, Visible:false);
        Word.Table wordTable = wordDoc.Tables[1];

        //初始宣告
        string ErrorMessage = null;
        bool 是否成功匯入 = true;
        string FileName = xlWorkbooks.Name;
        string SheetName = null;
		
        try
        {
            //事前檢查
            if (db.員工.Any(x => x.員工編號 == FileName))
            {
                員工 emp = db.員工.FirstOrDefault(x => x.員工編號 == FileName);
                db.Configuration.ValidateOnSaveEnabled = false;
                //設定狀態為可編輯
                db.Entry(emp).State = EntityState.Modified;

                員工 xl員工 = new 員工
                {	
                    員工編號 = FileName,
                    員工姓名 = wordTable.Cell(1,2).Range.Text.Trim().Replace("\r\a", string.Empty),			
                    生日 = wordTable.Cell(2,2).Range.Text.Trim().Replace("\r\a", string.Empty)
                };

                //匯入DB
                if (emp != null)
                {
                    //更新, 此法無法用在啟用自動編號的表,新的Class會給該屬性null,卡到主鍵無法更新
                    //改成一個一個更新,如下
                    //emp.員工編號 = xl員工.員工編號;
                    //emp.員工姓名 = xl員工.員工姓名;
                    //emp.員工生日 = xl員工.員工生日;
                    db.Entry(emp).CurrentValues.SetValues(xl員工);
                }
                else
                {
                    //新增
                    db.員工.Add(xl員工);
                }
            }
            else
            {
                throw new Exception(FileName + " 無此人資料!")
            }
        }
        catch (Exception ex)
        {
            ErrorMessage = "[" + SheetName + "] " + ex.Message;
            是否成功匯入 = false;
        }
        finally
        {
            //寫Log紀錄
            db.資料匯入紀錄.Add(new 資料匯入紀錄
            {
                員工編號 = FileName,
                員工姓名 = emp.員工姓名,				
                資料類型 = Event,
                匯入時間 = DateTime.Now,
                是否成功 = 是否成功匯入,
                失敗原因 = ErrorMessage
            });
			
            //最後一次執行儲存指令,刷新DB資料
            db.SaveChanges();
			
            //關閉工作簿
            wordDoc.Close();
			
            //讀完檔案後處理
            移動檔案(MemberPath, Event, 是否成功匯入)
        }
    }	
    //所有檔案讀完後,關閉Excel應用程式
    wordApp.Quit();
}

匯入Excel:

static public void Excel匯入(string EventsPath, string Event)
{
    //連接Entity Framework
    EntityDB db = new EntityDB();

    //開啟Excel應用程式
    Excel.Application xlApp = new Excel.Application
    {
        DisplayAlerts = false,	//關閉警告
        Visible = false,	//背景執行
    };

    //讀取資料夾檔案,但排除開啟時產生的"~$"開頭的隱藏暫存檔
    foreach(string MemberPath in Directory.GetFiles(EventsPath, @"*.*").Where(x => !x.Contains("~")))
    {
        //開啟路徑檔案
        Excel.Workboos xlWorkbook = xlApp.Workbooks.Open(MemberPath);

        //初始宣告
        string ErrorMessage = null;
        bool 是否成功匯入 = true;
        string FileName = xlWorkbooks.Name;
        string SheetName = null;
		
        try
        {
            //事前檢查
            if (db.員工.Any(x => x.員工編號 == FileName))
            {
                員工 emp = db.員工.FirstOrDefault(x => x.員工編號 == FileName);
                db.Configuration.ValidateOnSaveEnabled = false;
                //設定狀態為可編輯
                db.Entry(emp).State = EntityState.Modified;
            }
            else
            {
                throw new Exception(FileName + " 無此人資料!")
            }

            //將每個sheet資料分別匯入
            //只有一個sheet時,直接Excel.Worksheet xlWorksheet = xlWorkbook.Sheets[1];
            //註:Excel的Sheet編號是從1開始,不是0
            foreach (Excel.Worksheet xlWorksheet in xlWorkbook.Sheets)
            {
                switch (SheetName = xlWorksheet.Name)
                {
                    case "SheetName1":
                        //先將Excel資料放入目標表的新class
                        //讀取Excel須數格子,讀取方式分Text, Value, Value2
                        //可上網查詢讀出來的差異在哪
                        員工 xl員工 = new 員工
                        {	
                            員工編號 = FileName,
                            員工姓名 = xlWorksheet.Cells[1, 2].Text,			
                            生日 = xlWorksheet.Cells[2, 2].Value,							
                            //一併用列舉的方式變成編號抓值
                            層級 = (int)Enum.Parse(typeof(Enum層級), xlWorksheet.Cells[4, 2].Value2)
                        };

                        //匯入DB
                        if (emp != null)
                        {
                            //更新, 此法無法用在啟用自動編號的表,新的Class會給該屬性null,卡到主鍵無法更新
                            //改成一個一個更新,如下
                            //emp.員工編號 = xl員工.員工編號;
                            //emp.員工姓名 = xl員工.員工姓名;
                            //emp.員工生日 = xl員工.員工生日;
                            db.Entry(emp).CurrentValues.SetValues(xl員工);
                        }
                        else
                        {
                            //新增
                            db.員工.Add(xl員工);
                        }
                        break;
                    case "SheetName2":
                        //todo somethings
                        break;
                    case "SheetName3":
                        //todo somethings
                        break;
                }
            }
        }
        catch (Exception ex)
        {
            ErrorMessage = "[" + SheetName + "] " + ex.Message;
            是否成功匯入 = false;
        }
        finally
        {
            //寫Log紀錄
            db.資料匯入紀錄.Add(new 資料匯入紀錄
            {
                員工編號 = FileName,
                員工姓名 = emp.員工姓名,				
                資料類型 = Event,
                匯入時間 = DateTime.Now,
                是否成功 = 是否成功匯入,
                失敗原因 = ErrorMessage
            });
			
            //最後一次執行儲存指令,刷新DB資料
            db.SaveChanges();
			
            //關閉工作簿
            xlWorkbook.Close();
			
            //讀完檔案後處理
            移動檔案(MemberPath, Event, 是否成功匯入)
        }
    }
	
    //所有檔案讀完後,關閉Excel應用程式
    xlApp.Quit();
}

後處理:移動檔案

static public void 移動檔案(string FilePath, string Event, bool 是否成功匯入)
{
    //連接Entity Framework
    EntityDB db = new EntityDB();

    //初始宣告
    string ErrorMessage = "[移動檔案]" + FilePath;
    bool 是否成功移動檔案 = true;

    try
    {
        //失敗檔案移動至目標資料夾,資料夾插入位置可用IndexOf(檔案名稱)或其他方式自己數
        string DestinationPath = FilePath.Insert(40, @"\失敗的檔案");
		
        if (!是否成功匯入)
        {
            File.Move(FilePath, DestinationPath);
        }
        //刪除原檔案
        FileInfo fi = new FileInfo(FilePath);
        fi.Delete;
    }
    catch (Exception ex)
    {
        ErrorMessage = ErrorMessage + " → " + ex.Message;
        是否成功移動檔案 = false;
    }
    finally
    {
        //寫Log紀錄
        db.資料匯入紀錄.Add(new 資料匯入紀錄
        {
            員工編號 = 0,
            員工姓名 = "MyConsole",				
            資料類型 = Event,
            匯入時間 = DateTime.Now,
            是否成功 = 是否成功移動檔案,
            失敗原因 = ErrorMessage
        });
		
        //最後一次執行儲存指令,刷新DB資料
        db.SaveChanges();	
    }
}