C# winform实现导入大量Excel数据到TreeList界面中且批量提交后台

       现在有这样一个需求:Excel中存放的是上万条甚至更多商品数据,包括数量、单价,分类等等很多属性,以树形展示,多级分类。我需要将Excel数据导入到TreeList中,不着急提交到后台,我还要改一些商品价格和数量,对应的分类要显示下面所有商品总金额,处理完要改的数据再提交后台。

思路:1、先将Excel转DataTable(两种方式,推荐第二种)

           2、将DataTable和现有列表数据合并作为新的数据源绑定到TreeList(或者与源列表数据进行对比,已存在的商品更新信息,不存在的添加进来。),这里导入数据到界面不要对父节点做任何处理,只更新商品信息。

           3、重新计算父节点分类的金额(递归),导入数据,界面展示就算完成

           4、提交后台采用 创建数据库临时表(#temp),先将所有数据存放在临时表,通过update select | insert select方式保存到数据库。

代码实现:

DataTable 转 List 参考

        /// 
        /// 导入操作  T表示商品信息类,ToDataTable Excel转DataSet方法
        /// 
        /// 
        /// 
        private void btImport_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            openFileDialog1.Filter = "Excel Files|*.xls;*.xlsx;*.xlsm";
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                List lstAllNode = treelist.GetNodeList();
                List sourceList= treelist.DataSource as List;
                DataTable ImportTable = ToDataTable(openFileDialog1.FileName).Tables[0];
                //验证文档格式是否正确
                if (ImportTable == null || ImportTable.Rows.Count == 0) 
                    throw new Exception("无导入数据"); 
                bool validityFormat = true;
                if (!ImportTable.Columns.Contains("编号")) 
                    validityFormat = false; 
                if (!ImportTable.Columns.Contains("数量")) 
                    validityFormat = false; 
                if (!validityFormat) 
                    throw new Exception("文档格式不正确,请重新导入"); 
                List dtToList = ConvertToModel(ImportTable);
                dtToList.Foreach(m=>{
                    if(sourceList.Exists(x=>x.Code=m.Code))
                        {
                            //更新商品信息
                        }
                    else
                        {
                            sourceList.Add(m);
                        }
                }); 
                treelist.RefreshDataSource(); 
                //遍历所有子节点,递归计算父节点。
                foreach (TreeListNode node in treelist.GetNodeList().FindAll(x => !x.HasChildren))
                {
                     //调用递归方法(子节点的父节点只计算一次,如果父节点下有1W个子节点,按照这种遍历子节点方式会重复计算这个父节点1W次,显然效率会很低,认定这1W个子节点有相同的父节点,至计算一次即可)
                     CalculationNodeValue();   
                } 
                treelist.RefreshDataSource();
                XtraMessageBox.Show("数据成功导入到程序中,保存后生效!");
            }
        }
        /// 
        /// 导入的数据在递归计算父节点数据是用于存储已计算过的父节点
        /// 
        List ExistParentNode = new List();
        private void CalculationNodeValue(TreeListNode node)
        { 
            if (node.ParentNode != null && !ExistParentNode.Exists(x=>(tlDetail.GetDataRecordByNode(x) as T).ItemCode == (tlDetail.GetDataRecordByNode(node.ParentNode) as T).Code))
            {
                if(!node.HasChildren)
                    ExistParentNode.Add(node.ParentNode); 
                T parententity = tlDetail.GetDataRecordByNode(node.ParentNode) as T;
                T entity = tlDetail.GetDataRecordByNode(node) as T;
                if (entity.Amount.HasValue)
                {
                    decimal totalthisamount = 0; 
                    foreach (TreeListNode childnode in node.ParentNode.Nodes)
                    {
                        if ((tlDetail.GetDataRecordByNode(childnode) as T).Amount.HasValue)
                            totalthisamount = totalthisamount + (tlDetail.GetDataRecordByNode(childnode) as T).Amount.Value; 
                    }
                    parententity.Amount = totalthisamount; 
                }
                CalculationNodeValue(node.ParentNode);
            }

        }

本文展示皆为关键代码,看懂逻辑。直接copy是没法运行的。

创建临时表批量更新数据

        private void BulkUpdate(List lstDetails, string operationBy, SqlTransaction tran)
        {
            if (lstDetails == null || lstDetails.Count == 0)
                return; 
            List lstColumnNames = new List()  //数据表列名
            {
                "Code",
                "Price",
                "Qty", 
                "Amount" 
            };
            //创建数据表
            DataTable dtStakes = ConvertToDataTable(lstDetails);
            //去除多余列
            for (int index = dtStakes.Columns.Count - 1; index >= 0; index--)
            {
                if (!lstColumnNames.Exists(m => m == dtStakes.Columns[index].ColumnName))
                {
                    dtStakes.Columns.RemoveAt(index);
                }
            }

            //创建SqlCommand对象
            SqlCommand cmd = tran.Connection.CreateCommand();
            cmd.Transaction = tran;
            cmd.CommandType = CommandType.Text;

            //获取Create临时表的SQL
            string sql = GetCreateTableSql(dtStakes, "#tmp", "被复制的表");
            cmd.CommandText = sql;
            cmd.ExecuteNonQuery();

            //

            //批量将数据插入临时表
            SqlBulkCopy bulkCopy = new SqlBulkCopy(tran.Connection, SqlBulkCopyOptions.Default, tran);
            using (bulkCopy)
            {
                bulkCopy.BatchSize = dtStakes.Rows.Count;
                #region 数据表和数据库中临时表的字段映射
                bulkCopy.ColumnMappings.Add("Code", "Code");
                bulkCopy.ColumnMappings.Add("Price", "Price"); 
                bulkCopy.ColumnMappings.Add("Qty", "Qty"); 
                bulkCopy.ColumnMappings.Add("Amount", "Amount"); 
                 
                #endregion

                bulkCopy.DestinationTableName = "#tmp";
                bulkCopy.WriteToServer(dtStakes);

            }

            //批量更新数据
            cmd.CommandText = String.Format(@"
            USE 库
            UPDATE Table A
			   SET A.Price= b.Price
				  ,A.Qty= b.Qty
				  ,A.Amount= b.Amount 
				  FROM Table A
				  INNER JOIN #tmp b on a.Code=b.Code " );
            cmd.CommandTimeout = 660;
            cmd.ExecuteNonQuery();
        }

 

你可能感兴趣的:(C#+winform,DevExpress)