使用C#将CSV数据导入SQL Server失败的问题求助
CSV导入SQL Server失败排查与解决方案
问题描述
在ASP.NET Core项目中实现CSV数据导入SQL Server功能时,点击导入按钮后仅前端控制台输出数组格式的更新数据,后端ImportData接口无插入执行记录,数据未写入数据库。
核心原因
- 前端未触发后端接口:当前
importBtn的点击事件仅打印数据,未通过AJAX或表单提交将数据发送到ImportData接口。 - 数据格式不兼容:前端收集的是二维数组,后端
ImportData接收的是ImportModel(包含FileContent字符串),格式不匹配。 - 异常信息未暴露:后端
catch块未输出详细异常,无法排查插入过程中的潜在错误。
解决方案
1. 前端修改:实现请求发送与格式转换
首先在页面中添加防伪令牌(ASP.NET Core默认启用防CSRF校验),可放在表单或页面底部:
@Html.AntiForgeryToken()
然后修改importBtn的点击事件,将表格数据转为标准CSV格式并发送到后端接口:
importBtn.addEventListener('click', function () { // 将表格数据转换为标准CSV格式(处理含逗号的单元格) let csvContent = ''; const rows = editableTable.getElementsByTagName('tr'); for (let i = 0; i < rows.length; i++) { const cells = rows[i].getElementsByTagName('td'); const rowData = []; for (let j = 0; j < cells.length; j++) { // 转义双引号并包裹含特殊字符的单元格 const cellValue = cells[j].innerText.replace(/"/g, '""'); rowData.push(`"${cellValue}"`); } csvContent += rowData.join(',') + '\n'; } // 发送POST请求到ImportData接口 fetch('/Import/ImportData', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value }, body: `FileContent=${encodeURIComponent(csvContent)}` }) .then(response => { if (!response.ok) throw new Error('请求失败'); return response.text(); }) .then(() => { alert('数据导入成功!'); clearBtn.click(); // 导入成功后清空页面 }) .catch(error => { console.error('导入错误:', error); alert('数据导入失败,请查看控制台日志'); }); });
2. 后端修改:完善异常日志与数据校验
更新ImportData方法,添加详细异常日志和基础数据类型校验:
[HttpPost] public IActionResult ImportData(ImportModel model) { if (!string.IsNullOrEmpty(model.FileContent)) { var connectionString = Configuration.GetConnectionString("DefaultConnection"); using (var connection = new SqlConnection(connectionString)) { connection.Open(); using (var transaction = connection.BeginTransaction()) { try { var rows = model.FileContent.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); foreach (var row in rows) { var cells = row.Split(","); // 校验列数是否匹配数据库表结构 if (cells.Length != 11) { throw new InvalidOperationException($"行数据列数错误,预期11列,实际{cells.Length}列:{row}"); } // 执行插入逻辑 var insertCommand = "INSERT INTO dbo.DEV (EmployeeID, FullName, JobTitle, Department, BusinessUnit, Gender, Ethnicity, Age, HireDate, Country, City) VALUES (@EmployeeID, @FullName, @JobTitle, @Department, @BusinessUnit, @Gender, @Ethnicity, @Age, @HireDate, @Country, @City)"; using (var command = new SqlCommand(insertCommand, connection, transaction)) { // 去除CSV单元格的引号包裹 command.Parameters.AddWithValue("@EmployeeID", cells[0].Trim('"')); command.Parameters.AddWithValue("@FullName", cells[1].Trim('"')); command.Parameters.AddWithValue("@JobTitle", cells[2].Trim('"')); command.Parameters.AddWithValue("@Department", cells[3].Trim('"')); command.Parameters.AddWithValue("@BusinessUnit", cells[4].Trim('"')); command.Parameters.AddWithValue("@Gender", cells[5].Trim('"')); command.Parameters.AddWithValue("@Ethnicity", cells[6].Trim('"')); // 转换Age为整数类型 if (!int.TryParse(cells[7].Trim('"'), out int age)) { throw new InvalidOperationException($"年龄格式错误:{cells[7]}"); } command.Parameters.AddWithValue("@Age", age); // 转换HireDate为日期类型 if (!DateTime.TryParse(cells[8].Trim('"'), out DateTime hireDate)) { throw new InvalidOperationException($"入职日期格式错误:{cells[8]}"); } command.Parameters.AddWithValue("@HireDate", hireDate); command.Parameters.AddWithValue("@Country", cells[9].Trim('"')); command.Parameters.AddWithValue("@City", cells[10].Trim('"')); int affectedRows = command.ExecuteNonQuery(); Console.WriteLine($"执行插入,影响行数:{affectedRows}"); } } transaction.Commit(); Console.WriteLine("数据导入成功"); return Ok("导入成功"); } catch (Exception ex) { transaction.Rollback(); var errorMsg = $"导入失败:{ex.Message}"; ModelState.AddModelError("", errorMsg); Console.WriteLine($"导入异常详情:{ex.ToString()}"); return BadRequest(errorMsg); } } } } return BadRequest("无有效文件内容"); }
3. 额外优化建议
- 性能优化:对于大文件,使用
SqlBulkCopy替代循环INSERT,大幅提升导入速度。 - CSV解析优化:使用第三方库(如
CsvHelper)处理复杂CSV格式,避免手动拆分导致的错误。 - 数据验证:给
ImportModel添加数据注解,在模型绑定阶段就校验输入合法性。
内容的提问来源于stack exchange,提问作者sadLife101
相关产品推荐
相关产品推荐

