C# .NET导出CSV函数泛化优化及重复查询问题求助
C# Oracle数据导出CSV代码优化
原代码存在以下问题:
- 同一Company_ID会被多次遍历并重复执行数据库查询
- 硬编码指定Company_ID的值(如10、1000)
- 首次查询仅用于遍历数据,属于冗余操作
优化要点
- 避免重复查询:先获取唯一的Company_ID列表,对每个ID只执行一次导出查询
- 移除硬编码:把需要处理的Company_ID改成方法参数传入,或者从配置文件读取,灵活调整目标对象
- 删除冗余查询:直接针对目标Company_ID查询导出数据,去掉无意义的初始遍历查询
- 安全与资源优化:用参数化查询防止SQL注入,用
using语句自动释放连接、流等资源,避免内存泄漏 - 代码复用:把重复的逻辑(比如生成文件名、查询数据、CSV值转义)抽成独立方法,让代码更整洁
优化后的完整代码
GetData函数及辅助查询方法
// 可传入需要处理的CompanyID列表,替代硬编码 DataTable GetData(List<int> targetCompanyIds) { string chargeMonth = DateTime.Now.ToString("yyyyMM"); string creationDate = DateTime.Now.ToString("yyyyMMdd"); string creationTime = DateTime.Now.ToString("HHmmss"); string constVal = "MLL"; string fileType = "HIYUV-CHEVRA"; var connectString = "Data Source=192.168.117.1;User ID=*;Password=*"; // using自动释放数据库连接资源 using (OracleConnection con = new OracleConnection(connectString)) { con.Open(); // 对CompanyID去重,避免重复查询 foreach (int companyId in targetCompanyIds.Distinct()) { // 拼接文件名 string fileName = $"{constVal}-{fileType}-{companyId}-{chargeMonth}-{creationDate}-{creationTime}.csv"; // 查询当前CompanyID的导出数据 DataTable exportData = GetExportDataByCompanyId(con, companyId); // 执行CSV导出 ExportExcelGeneric(exportData, fileName); } // 若业务仍需要返回初始查询结果,保留此部分;不需要可直接删除 using (OracleCommand cmd = con.CreateCommand()) { cmd.CommandText = "Select * from BAKASHOT_PIRTY_MEIDA WHERE PROD IS NULL and CHARGED = 0"; DataTable dt = new DataTable(); dt.Load(cmd.ExecuteReader()); return dt; } } } // 提取查询逻辑为独立方法,复用代码 DataTable GetExportDataByCompanyId(OracleConnection connection, int companyId) { using (OracleCommand cmd = connection.CreateCommand()) { // 参数化查询,防止SQL注入 cmd.CommandText = "Select * from BAKASHOT_PIRTY_MEIDA WHERE COMPANY_ID = :CompanyId and PROD IS NULL and CHARGED = 1"; cmd.Parameters.Add(":CompanyId", OracleDbType.Int32).Value = companyId; DataTable dt = new DataTable(); dt.Load(cmd.ExecuteReader()); return dt; } }
优化后的CSV导出函数
void ExportExcelGeneric(DataTable dataTable, string filename) { // 用Path.Combine处理路径,避免语法错误 string filePath = Path.Combine(@"D:\", filename); // using自动释放StreamWriter资源 using (StreamWriter sw = new StreamWriter(filePath, false, Encoding.UTF8)) { // 写入表头 for (int i = 0; i < dataTable.Columns.Count; i++) { sw.Write(EscapeCsvValue(dataTable.Columns[i].ColumnName)); if (i < dataTable.Columns.Count - 1) { sw.Write(","); } } sw.WriteLine(); // 写入数据行 foreach (DataRow dr in dataTable.Rows) { for (int i = 0; i < dataTable.Columns.Count; i++) { if (!Convert.IsDBNull(dr[i])) { sw.Write(EscapeCsvValue(dr[i].ToString())); } if (i < dataTable.Columns.Count - 1) { sw.Write(","); } } sw.WriteLine(); } } } // 提取CSV值转义逻辑,处理逗号、双引号、换行等特殊情况 string EscapeCsvValue(string value) { if (value.Contains(',') || value.Contains('"') || value.Contains('\n') || value.Contains('\r')) { // 转义双引号,用双引号包裹内容 return $"\"{value.Replace("\"", "\"\"")}\""; } return value; }
额外建议
- 配置化管理:把数据库连接字符串、目标CompanyID、文件存储路径放到配置文件(如appsettings.json)中,彻底消除硬编码
- 错误处理:添加try-catch块捕获数据库操作、文件写入的异常,提升程序稳定性
- 日志记录:记录导出的CompanyID、文件名、成功/失败状态,方便后续排查问题
内容的提问来源于stack exchange,提问作者user20622377
相关产品推荐
相关产品推荐

