You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用C#将CSV数据导入SQL Server失败的问题求助

CSV导入SQL Server失败排查与解决方案

问题描述

在ASP.NET Core项目中实现CSV数据导入SQL Server功能时,点击导入按钮后仅前端控制台输出数组格式的更新数据,后端ImportData接口无插入执行记录,数据未写入数据库。

核心原因

  1. 前端未触发后端接口:当前importBtn的点击事件仅打印数据,未通过AJAX或表单提交将数据发送到ImportData接口。
  2. 数据格式不兼容:前端收集的是二维数组,后端ImportData接收的是ImportModel(包含FileContent字符串),格式不匹配。
  3. 异常信息未暴露:后端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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 09:37:36