將不規則Excel文件數據寫入數據庫
此次是要將以下Excel文件裏面的數據寫入火車訂票系統數據庫表裏面。那我們先來看看是什麼樣子的Excel數據。
這個文件裏面共有2個工作表,裏面的數據按上圖樣式排列。接下來看我們要導入的數據庫表。
上圖有3張表,其中TrainType爲火車類型表,存儲的是火車的類型,比如普通車,動車組等。
TrainTrip存儲的是火車的車次,ReachStation存儲的是火車的到達站點,由於起始站都是福州,
所以表暫且這麼設計了。
按照上圖Excel的格式,如果按常規的數據源來讀取數據肯定是行不通的,應該採用更靈活的方式來,
所以可以利用程序的循環來讀取每一單元格的信息。通過網上的不斷尋找終於讓我找到一個開源的讀取
Excel格式文件的代碼NExcel。想了解更多的可以直接去訪問官方網站http://nexcel.sourceforge.net/
那麼再開始我們的程序代碼之前先看看我們的程序界面吧。
該界面實現的是先上傳文件,然後把文件裏面的數據導入到數據庫裏面,文件的路徑暫且保存到Session裏面。
接下來就是代碼啦:
if (this.IsValid && txtCheckCode.Text.ToLower() == Convert.ToString(Session["checkCode"]).ToLower()) { try { using (SqlConnection conn = new SqlConnection(SqlHelper.ConnectionString)) { conn.Open(); SqlDataAdapter sdaTrainType = new SqlDataAdapter("Select * From TrainType", conn); SqlDataAdapter sdaTrainTrip = new SqlDataAdapter("Select * From TrainTrip", conn); SqlDataAdapter sdaReachStation = new SqlDataAdapter("Select * From ReachStation", conn); SqlCommandBuilder builderTrainType = new SqlCommandBuilder(sdaTrainType); SqlCommandBuilder builderTrainTrip = new SqlCommandBuilder(sdaTrainTrip); SqlCommandBuilder builderReachStation = new SqlCommandBuilder(sdaReachStation); SqlCommand cmdTrainType = builderTrainType.GetInsertCommand(); SqlCommand cmdTrainTrip = builderTrainTrip.GetInsertCommand(); SqlCommand cmdReachStation = builderReachStation.GetInsertCommand(); DataSet ds = new DataSet(); sdaTrainType.Fill(ds, "TrainType"); sdaTrainTrip.Fill(ds, "TrainTrip"); sdaReachStation.Fill(ds, "ReachStation"); DataTable trainType = ds.Tables["TrainType"]; DataTable trainTrip = ds.Tables["TrainTrip"]; DataTable reachStation = ds.Tables["ReachStation"]; // Excel數據操作 string filepath = Server.MapPath(Session["FileName"].ToString()); Workbook workbook = Workbook.getWorkbook(filepath); int trainTypeId = 1; int trainTripId = 1; int reachStationId = 1; foreach (Sheet sheet in workbook.Sheets) { //添加數據到TrainType DataRow trainTypeRow = trainType.NewRow(); trainTypeRow["ID"] = trainTypeId++; trainTypeRow["Name"] = sheet.Name; trainType.Rows.Add(trainTypeRow); for (int irow = 1; irow < sheet.Rows; irow = irow + 3) { // 添加數據到TrainTrip if (sheet.getCell(0, irow).Contents != "") { DataRow trainTripRow = trainTrip.NewRow(); trainTripRow["ID"] = trainTripId++; trainTripRow["TripName"] = sheet.getCell(0, irow).Contents; trainTripRow["StartTime"] = sheet.getCell(1, irow).Contents; trainTripRow["TypeID"] = trainTypeId - 1; trainTripRow["TicketCount"] = 0; trainTrip.Rows.Add(trainTripRow); } // 添加數據到ReachStation for (int icol = 2; icol < sheet.Columns; icol++) { if (sheet.getCell(icol, irow).Contents == "") { break; // 到達站爲空則退出循環 } DataRow reachStationRow = reachStation.NewRow(); reachStationRow["ID"] = reachStationId++; reachStationRow["Name"] = sheet.getCell(icol, irow).Contents; reachStationRow["ReachTime"] = sheet.getCell(icol, irow + 1).Contents; reachStationRow["HardSeatPrice"] = sheet.getCell(icol, irow + 2).Contents; reachStationRow["AdvancePrice"] = Common.GetAdvancePrice(Convert.ToDecimal(sheet.getCell(icol, irow + 2).Contents)); reachStationRow["TripID"] = trainTripId - 1; reachStationRow["TicketCount"] = 0; reachStation.Rows.Add(reachStationRow); } } } sdaTrainType.Update(ds, "TrainType"); sdaTrainTrip.Update(ds, "TrainTrip"); sdaReachStation.Update(ds, "ReachStation"); workbook.close(); lblMsg.Text = "導入數據成功!"; } } catch { lblMsg.Text = "導入數據失敗!"; } } else { lblMsg.Text = "驗證碼錯誤!"; }
此次整個系統的製作需求一直再改,我是弄得筋疲力盡了。不過現在把一些感想記在此處。
首先數據庫的設計,如果涉及到數據庫導入的話,應該考慮到表ID是否要弄成非自增量,否則將給後面的開發造成一定的困難。
還有時間字段問題,如果時間爲12:00並未有日期的話,涉及到數據庫導出到Excel應該設置爲字符串類型,而不是datetime類型。
整個系統數據庫設計到多個表數據刪除問題,應該考慮是否添加外鍵約束,如果有外鍵約束可能最終造成多個表因爲互相關聯導致數據刪除
無法順利進行。
接着是程序的設計,記着不要一直追求代碼的最簡潔化,該多寫幾句還是得寫,不要怕重複,就像上面那段我把datatable更新到數據庫的
代碼,我一直想只用一個SqlDataAdapter就做完所有的數據操作,我想該多寫幾個SqlDataAdapter還是得多寫的。以上純屬個人見解。