使用SqlBulkCopy類實現匯入excel表格

weixin_34120274發表於2013-11-01

 

前言:

        上篇部落格介紹了SqlBulkCopy類批量運算元據庫的相關操作,最後提到了可以使用這個類實現excel檔案匯入資料庫,接下來我做簡單介紹。

首先說一下思路:

  1. excel中的資料讀出來並放入到DataTable中。
  2. 使用SqlBulkCopy類的方法批量匯入資料庫。

        雖然只用簡單的兩部。但是我們需要考慮的問題還是用很多的,其中很重要的一點就是判斷需要匯入即excel中的資料是否合法,包括:是不是為空,是不是太長,是不是有重複,匯入的欄位是否對應。看起來挺嚇人的,其實思路還是最重要的。只要敢想什麼都能實現。

        下面我簡單的寫一個小例子來說明一下。

        多餘的不說,直接到點選匯入按鈕:

 

        protected void btnImportTeacher_Click(object sender, EventArgs e)
        {
            //成員業務邏輯層
            MemberInfoBLL  memberInfo = new MemberInfoBLL() ;
            //BLL層把Excel轉化為datatable類
            CreateExcelDataBLL  createExcelData = new CreateExcelDataBLL();
            //將錯誤資訊匯出到Excel           
            DataTableToExcel dataTableToExcel = new DataTableToExcel();
            /*-------------------------------------準備Excel檔案--------------------------------------*/
            //獲取上傳檔案地址
            string url = fupImportTeacher.PostedFile.FileName.ToString();

            if (url == "")
            {
                //資料來源為空,彈出提示:請選擇Excel檔案!
                Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('請選擇Excel檔案!');</script>");
                return;
            }

            string urlLocation = url.Substring(url.LastIndexOf("\\") + 1);//獲取檔名

            DataTable dtAllMember;
            //在系統中建資料夾up,並將excel檔案另存
            this.fupImportTeacher.SaveAs(Server.MapPath("~\\UploadFile") + "\\" + urlLocation);//記錄檔名到伺服器相對應的資料夾中

            //獲得檔案路徑
            string strpath = Server.MapPath("~\\UploadFile") + "\\" + urlLocation;

            //把上傳的Excel轉換為datatable
            dtAllMember = createExcelData.CreateExcelDataSource(strpath);


         以上程式碼涉及到的類包括CreateExcelDataBLL  、DataTableToExcel 

 

 

/*******************************************************************************
 *文    件:CreateExcelDataBLL.cs
 *作    者:韓義
 *所屬小組:圖書館維修管理系統
 *檔案說明:基礎系統-把excel轉化為datatable
 *建立日期:2013年1月23日9:43:16
 *修改作者:
 *修改日期:
 *修改描述:
 *版 本 號:V1.0
 *版本號變更記錄:     
********************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

//引用各名稱空間
using System.Data;
using System.Data.OleDb;
using System.Data.SqlClient;
using System.IO;

namespace BLL
{
    public class CreateExcelDataBLL
    {
        //構造方法
        public CreateExcelDataBLL()
        {
           
        }
        /// <summary>
        /// 傳入excel路徑,轉換為datatable
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public DataTable CreateExcelDataSource(string url)
        {
            //定義一個DataTable資料表
            DataTable dt = null;

            //獲得excel資料
            string connetionStr = "Provider=Microsoft.Jet.OleDb.4.0;" + "data source=" + url + ";Extended Properties='Excel 8.0; HDR=YES; IMEX=1'";
            //從Excel表的Sheet1單元格獲取資料
            string strSql = "select * from [Sheet1$]";
            OleDbConnection oleConn = new OleDbConnection(connetionStr);

            OleDbDataAdapter oleAdapter = new OleDbDataAdapter(strSql, connetionStr);
            try
            {
                //把Excel資料填充給DataTable
                dt = new DataTable();
                oleAdapter.Fill(dt);
                //返回資料表
                return removeEmpty(dt);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                oleAdapter.Dispose();
                oleConn.Close();
                oleConn.Dispose();
                //刪除上傳的Excel檔案(因為該檔案的存在會佔用多餘的網站空間)
                if (File.Exists(url))
                {
                    File.Delete(url);
                }
            }
        }
        /// <summary>
        /// 迴圈去除datatable中的空行
        /// </summary>
        /// <param name="dt"></param>
        protected DataTable removeEmpty(DataTable dt)
        {
            List<DataRow> removelist = new List<DataRow>();
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                bool rowdataisnull = true;
                for (int j = 0; j < dt.Columns.Count; j++)
                {

                    if (!string.IsNullOrEmpty(dt.Rows[i][j].ToString().Trim()))
                    {

                        rowdataisnull = false;
                    }

                }
                if (rowdataisnull)
                {
                    removelist.Add(dt.Rows[i]);
                }

            }
            for (int i = 0; i < removelist.Count; i++)
            {
                dt.Rows.Remove(removelist[i]);
            }
            return dt; 
        }
    }
}

 

/*******************************************************************************
 *文    件:DataTableToExcel.cs
 *作    者:韓義
 *所屬小組:圖書館維修管理系統
 *檔案說明:基礎系統-把datatable轉化為excel
 *建立日期:2013年1月23日10:43:16
 *修改作者:
 *修改日期:
 *修改描述:
 *版 本 號:V1.0
 *版本號變更記錄:     
********************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//匯入名稱空間
using System.Data;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
namespace BLL
{
    public class DataTableToExcel
    {
        /// <summary>
        /// 匯出Excel
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="ExportFileName"></param>
        public void ToExcel(DataTable dt)
        {
            DataGrid dgExcel = new DataGrid();
            dgExcel.DataSource = dt;
            dgExcel.DataBind();

            HttpContext.Current.Response.Charset = "GB2312";
            string fileName = HttpUtility.UrlEncode(Guid.NewGuid().ToString(), System.Text.Encoding.UTF8);
            string str = "attachment;filename=" + fileName + ".xls";
            HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.UTF8;
            HttpContext.Current.Response.ContentType = "application/ms-excel";
            HttpContext.Current.Response.AppendHeader("content-disposition", str);
            StringWriter sw = new StringWriter();
            HtmlTextWriter htmTextWriter = new HtmlTextWriter(sw);
            dgExcel.RenderControl(htmTextWriter);
            HttpContext.Current.Response.Write("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />");
            string style = "<style>td{mso-number-format:\"\\@\";}</style>";//防止匯出excel時將以0開頭的全數字資料的0去掉
            HttpContext.Current.Response.Write(style);
            HttpContext.Current.Response.Write("</head><body>");
            HttpContext.Current.Response.Write(sw);
            HttpContext.Current.Response.Write("</body></html>");
            HttpContext.Current.Response.End();

        }
    }
}

 

 

         兩個類的作用我想通過上面的解釋大家都應該明白他們的作用了。

        驗證excel中資料的有效性:

        下面介紹如何驗證excel中資料的有效性。

            /*-------------------------------------判斷資料來源是否合法--------------------------------------*/
            //定義要求的欄位資料
            string[] headfields = { "成員姓名","學號","身份等級","小組名稱","密碼","性別","年齡","手機號","QQ號","郵箱","備註"};
            //判斷dtAllTeacher中是否包含全部要求的欄位
            for (int i = 0; i < headfields.Length; i++)
            {
                //只要有一個欄位不被包含,則提示"資料來源缺少必要的欄位",並退出迴圈和整個方法
                if (!dtAllMember.Columns.Contains(headfields[i]))
                {
                    Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('資料來源缺少必要的欄位,請檢查Excel資料來源!');</script>");
                    //退出方法
                    return;
                }
            }

            //判斷資料來源中是否有資料
            if (dtAllMember.Rows.Count == 0)
            {
                Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('Excel檔案中沒有任何資料,請填充資料!');</script>");
                //退出方法
                return;
            }

            //判斷是否有相同學號的行
            DataView dvTeacher = new DataView(dtAllMember);
            if (dvTeacher.Count != dvTeacher.ToTable(true, "學號").Rows.Count)
            {
                Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('Excel中有相同的學號,學號不能相同!');</script>");
                //退出方法
                return;
            }


            DataSet dsMember = new DataSet("dt_Member"); //建立一個名為dt_Member的DataSet

            //手動建立的新資料表-學生資料表
            DataTable dtAddMember = new DataTable("dt_AddMember"); //建立一個名為dt_AddMember的DataTalbe
            //為dt_AddMember表內建立Column(表頭),新增資料列:
            dtAddMember.Columns.Add(new DataColumn("memberName", typeof(string)));
            dtAddMember.Columns.Add(new DataColumn("memberStudentID", typeof(string)));
            dtAddMember.Columns.Add(new DataColumn("level", typeof(string)));
            dtAddMember.Columns.Add(new DataColumn("groupID", typeof(string)));
            dtAddMember.Columns.Add(new DataColumn("memberPW", typeof(string)));
            dtAddMember.Columns.Add(new DataColumn("sex", typeof(string)));
            dtAddMember.Columns.Add(new DataColumn("age", typeof(string)));
            dtAddMember.Columns.Add(new DataColumn("phone", typeof(string)));
            dtAddMember.Columns.Add(new DataColumn("qq", typeof(string)));
            dtAddMember.Columns.Add(new DataColumn("email", typeof(string)));
            dtAddMember.Columns.Add(new DataColumn("explian", typeof(string)));                     


            //新建資料表用於存放錯誤資料
            DataTable dtErrorRow = new DataTable();
            //為dtErrorRow建立列
            dtErrorRow.Columns.Add(new DataColumn("成員姓名", typeof(string)));
            dtErrorRow.Columns.Add(new DataColumn("學號", typeof(string)));
            dtErrorRow.Columns.Add(new DataColumn("身份等級", typeof(string)));
            dtErrorRow.Columns.Add(new DataColumn("小組名稱", typeof(string)));
            dtErrorRow.Columns.Add(new DataColumn("密碼", typeof(string)));
            dtErrorRow.Columns.Add(new DataColumn("性別", typeof(string)));
            dtErrorRow.Columns.Add(new DataColumn("年齡", typeof(string)));
            dtErrorRow.Columns.Add(new DataColumn("手機號", typeof(string)));
            dtErrorRow.Columns.Add(new DataColumn("QQ號", typeof(string)));
            dtErrorRow.Columns.Add(new DataColumn("郵箱", typeof(string)));
            dtErrorRow.Columns.Add(new DataColumn("備註", typeof(string)));            
            dtErrorRow.Columns.Add(new DataColumn("錯誤原因", typeof(string)));

            //從上傳的Excel轉換為的datatable表中取出資料,放入成員資訊。
            for (int intRow = 0; intRow < dtAllMember.Rows.Count; intRow++)
            {        
                
                //成員姓名
                strMemberName = dtAllMember.Rows[intRow]["成員姓名"].ToString();
                //成員姓名
                memberStudentID = dtAllMember.Rows[intRow]["學號"].ToString();
                strLevel = dtAllMember.Rows[intRow]["身份等級"].ToString();
                strGroupName = dtAllMember.Rows[intRow]["小組名稱"].ToString();
                
                strmemberPW = dtAllMember.Rows[intRow]["密碼"].ToString();
                strSex = dtAllMember.Rows[intRow]["性別"].ToString();
                strAge = dtAllMember.Rows[intRow]["年齡"].ToString();
                strPhone = dtAllMember.Rows[intRow]["手機號"].ToString();
                strQQ = dtAllMember.Rows[intRow]["QQ號"].ToString();
                
                strEmail = dtAllMember.Rows[intRow]["郵箱"].ToString();
                strExplian=dtAllMember.Rows[intRow]["備註"].ToString();               
              

                //根據小組名稱判斷,小組是否存在
                Boolean  bFlag = false;
                //判斷輸入的組名是否存在
                bFlag = new BLL.GroupInfoBLL().ExistsByName(strGroupName);                
               
                // ID
                if (bFlag ==true )
                {
                    //小組ID為--韓義
                    strGroupID = new BLL.GroupInfoBLL().GetModelByGroupName(strGroupName).groupID;
                }
                //否則將當前行新增到錯誤列表並跳出當前迴圈
                else
                {                    
                    //向錯誤列表中新增當前行
                    AddErrorRow(dtErrorRow, "指定的組名稱不存在");
                    //跳出當前迴圈
                    continue;
                }               
              
                //判斷成員ID是否存在
                bFlag = false;//定義標識變數
                //判斷學號是否存在
                bFlag = new BLL.MemberInfoBLL().Exists(memberStudentID);
                //如果指定的成員程式碼已存在則將當前行新增到錯誤列表,並跳出當前迴圈
                if (bFlag==true )
                {
                    //向錯誤列表中新增當前行
                    AddErrorRow(dtErrorRow, "指定的成員已存在");
                    //跳出當前迴圈
                    continue;
                }
                //判斷性別型別是否正確
                if (strSex != "男" && strSex != "女")
                {
                    //向錯誤列表中新增當前行
                    AddErrorRow(dtErrorRow, "成員性別錯誤");
                    //跳出當前迴圈
                    continue;
                }
                //判斷身份等級是否正確
                if (strLevel !="組員")
                {
                    //向錯誤列表中新增當前行
                    AddErrorRow(dtErrorRow, "匯入成員身份級別只能為“組員”,組長請在系統中指定");
                    //跳出當前迴圈
                    continue;
                }
                //判斷是否包含密碼資訊
                if (strmemberPW =="")
                {
                    //向錯誤列表中新增當前行
                    AddErrorRow(dtErrorRow, "成員密碼不能為空");
                    //跳出當前迴圈
                    continue;
                }
                //判斷是否包含電話資訊
                if (strPhone =="")
                {
                    //向錯誤列表中新增當前行
                    AddErrorRow(dtErrorRow, "成員手機號不能為空");
                    //跳出當前迴圈
                    continue;
                }
                //判斷是否包含郵箱資訊
                if (strEmail =="")
                {
                     //向錯誤列表中新增當前行
                    AddErrorRow(dtErrorRow, "成員郵箱不能為空");
                    //跳出當前迴圈
                    continue;
                }
                //判斷是否包含學號資訊
                if (memberStudentID == "")
                {
                    //向錯誤列表中新增當前行
                    AddErrorRow(dtErrorRow, "成員學號不能為空");
                    //跳出當前迴圈
                    continue;
                }
                //判斷是否包含姓名資訊
                if (strMemberName  == "")
                {
                    //向錯誤列表中新增當前行
                    AddErrorRow(dtErrorRow, "成員姓名不能為空");
                    //跳出當前迴圈
                    continue;
                }

                //新增成員資訊表的新行
                DataRow drAddMember = dtAddMember.NewRow();//注意這邊建立dt的新行的方法。指定型別是DataRow而不是TableRow,然後不用new直接的用建立的DataTable下面的NewRow方法。
                //學生資訊表對應的各列值
                drAddMember["memberName"] = strMemberName;
                drAddMember["memberStudentID"] = memberStudentID;
                drAddMember["level"] = strLevel;
                drAddMember["groupID"] = strGroupID;
                drAddMember["memberPW"] = strmemberPW;
                drAddMember["sex"] = strSex;
                drAddMember["age"] = strAge;
                drAddMember["phone"] = strPhone;
                drAddMember["qq"] = strQQ;
                drAddMember["email"] = strEmail;
                drAddMember["explian"] = strExplian;               
                dtAddMember.Rows.Add(drAddMember);  //將一整條資料寫入表中             
            }

            //將表加入DataSet中:成員資訊
            dsMember.Tables.Add(dtAddMember);


            //將DataSet中資料表匯入資料庫
            Boolean flagImportMember = memberInfo.ImportMember(dsMember);
            //判斷成員是否匯入成功
            if (true == flagImportMember && dtErrorRow.Rows.Count == 0)
            {
                //匯入成功,彈出提示
                Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('成員資訊匯入成功!');</script>");
            }
            else if (false == flagImportMember)
            {
                //匯入失敗,彈出提示
                Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('成員資訊匯入失敗!');</script>");
            }
            else if (true == flagImportMember && dtErrorRow.Rows.Count != 0)
            {
                //只有部分資料匯入成功,彈出提示
                Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('成員資訊只有部分匯入成功,有錯誤的部分已匯出為EXCEL,請檢視新匯出的EXCEL;新匯出的Excel修改錯誤後可作為資料來源重新匯入');</script>");
                //將錯誤資料匯出到Excel並開啟顯示
                dataTableToExcel.ToExcel(dtErrorRow);
            }
        }

 

         說明:以上程式碼中建立了兩個表一個用於匯入:欄位改為與資料庫對應,另一個表用於匯出:欄位改為漢字說明。其中memberInfo.ImportMember方法就是實現資料庫的批量匯入,這在上一篇部落格中已經有介紹了這裡就不再累述了。

        總結:

        原來感覺挺難的東西,現在都已經完整的總結了出來。體會挺深的,什麼東西首先不能被嚇住,平常心態對待每一個新知識,總會找到熟悉的身影,總有那麼個頭緒讓你一點一點屢清楚了。

 


 

相關文章