将不规则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还是得多写的。以上纯属个人见解。
欢迎转载,请注明出处