现在有这样一个需求:Excel中存放的是上万条甚至更多商品数据,包括数量、单价,分类等等很多属性,以树形展示,多级分类。我需要将Excel数据导入到TreeList中,不着急提交到后台,我还要改一些商品价格和数量,对应的分类要显示下面所有商品总金额,处理完要改的数据再提交后台。
思路:1、先将Excel转DataTable(两种方式,推荐第二种)
2、将DataTable和现有列表数据合并作为新的数据源绑定到TreeList(或者与源列表数据进行对比,已存在的商品更新信息,不存在的添加进来。),这里导入数据到界面不要对父节点做任何处理,只更新商品信息。
3、重新计算父节点分类的金额(递归),导入数据,界面展示就算完成
4、提交后台采用 创建数据库临时表(#temp),先将所有数据存放在临时表,通过update select | insert select方式保存到数据库。
代码实现:
/// <summary>
/// 导入操作 T表示商品信息类,ToDataTable Excel转DataSet方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btImport_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
openFileDialog1.Filter = "Excel Files|*.xls;*.xlsx;*.xlsm";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
List<TreeListNode> lstAllNode = treelist.GetNodeList();
List<T> sourceList= treelist.DataSource as List<T>;
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<T> 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("数据成功导入到程序中,保存后生效!");
}
}
/// <summary>
/// 导入的数据在递归计算父节点数据是用于存储已计算过的父节点
/// </summary>
List<TreeListNode> ExistParentNode = new List<TreeListNode>();
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<T> lstDetails, string operationBy, SqlTransaction tran)
{
if (lstDetails == null || lstDetails.Count == 0)
return;
List<string> lstColumnNames = new List<string>() //数据表列名
{
"Code",
"Price",
"Qty",
"Amount"
};
//创建数据表
DataTable dtStakes = ConvertToDataTable<T>(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();
}