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

Web API接收上传CSV字节数组,结合EF插入含附加字段的SQL Server数据

解决方案分步说明

1. 处理字节数组,解析CSV内容

首先得把内存里的字节数组转成可读取的流,然后用专业的CSV解析库处理——自己写解析逻辑很容易踩坑(比如带引号的字段、跨行内容这些情况),推荐用CsvHelper(直接通过NuGet安装就行)。

在Web API控制器里,先从表单数据里拿到三个附加字段,再处理CSV字节数组:

using CsvHelper;
using System.Globalization;
using System.IO;
using System.Data.SqlClient;

[HttpPost("upload-csv")]
public async Task<IActionResult> UploadCsv()
{
    // 读取上传的表单数据
    var form = await Request.ReadFormAsync();
    var file = form.Files["csvFile"];
    var field1 = form["field1"].ToString(); // 第一个附加字段
    var field2 = form["field2"].ToString(); // 第二个附加字段
    var field3 = form["field3"].ToString(); // 第三个附加字段

    if (file == null || file.Length == 0)
        return BadRequest("未上传有效文件");

    // 将文件流转为内存流(如果已经是字节数组,直接用MemoryStream包装即可)
    using var stream = new MemoryStream();
    await file.CopyToAsync(stream);
    stream.Position = 0; // 重置流的读取位置到开头

    // 用CsvHelper读取CSV内容
    using var reader = new StreamReader(stream);
    using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);

    // 定义CSV对应的实体类,字段和CSV表头对应
    var csvRecords = csv.GetRecords<CsvRecord>().ToList();

    // 给每条CSV记录添加上传的附加字段,映射到SQL表实体
    var recordsToInsert = csvRecords.Select(record => new YourSqlTableEntity
    {
        // 映射CSV字段到SQL表字段
        CsvColumn1 = record.Field1,
        CsvColumn2 = record.Field2,
        // ... 其他CSV字段
        // 添加上传的附加字段
        ExtraField1 = field1,
        ExtraField2 = field2,
        ExtraField3 = field3
    }).ToList();

    // 批量插入到SQL Server
    await BulkInsertToSql(recordsToInsert);

    return Ok($"成功插入 {recordsToInsert.Count} 条记录");
}

2. 定义对应的实体类

需要两个实体类:一个对应CSV的结构,一个对应SQL Server表的结构:

// CSV记录实体,字段名要和CSV表头匹配,也可以用特性配置映射
public class CsvRecord
{
    public string Field1 { get; set; }
    public string Field2 { get; set; }
    // ... 其他CSV列对应的属性
}

// SQL Server表对应的实体,字段名要和表列名匹配
public class YourSqlTableEntity
{
    public string CsvColumn1 { get; set; }
    public string CsvColumn2 { get; set; }
    public string ExtraField1 { get; set; }
    public string ExtraField2 { get; set; }
    public string ExtraField3 { get; set; }
    // ... 其他表列属性
}

3. 实现高效批量插入

用SqlBulkCopy做批量插入,比逐条执行Insert语句效率高太多,尤其适合大量数据的场景:

private async Task BulkInsertToSql(List<YourSqlTableEntity> records)
{
    var connectionString = "你的SQL Server连接字符串"; // 替换成实际连接串

    using var connection = new SqlConnection(connectionString);
    await connection.OpenAsync();

    using var bulkCopy = new SqlBulkCopy(connection);
    bulkCopy.DestinationTableName = "你的SQL表名"; // 替换成目标表名

    // 映射实体属性到表列(如果属性名和列名完全一致,可以省略这一步)
    bulkCopy.ColumnMappings.Add("CsvColumn1", "CsvColumn1");
    bulkCopy.ColumnMappings.Add("CsvColumn2", "CsvColumn2");
    bulkCopy.ColumnMappings.Add("ExtraField1", "ExtraField1");
    bulkCopy.ColumnMappings.Add("ExtraField2", "ExtraField2");
    bulkCopy.ColumnMappings.Add("ExtraField3", "ExtraField3");
    // ... 其他列的映射

    // 把实体列表转成DataTable(也可以用IEnumerable直接传入,DataTable兼容性更强)
    var dataTable = new DataTable();
    dataTable.Columns.Add("CsvColumn1", typeof(string));
    dataTable.Columns.Add("CsvColumn2", typeof(string));
    dataTable.Columns.Add("ExtraField1", typeof(string));
    dataTable.Columns.Add("ExtraField2", typeof(string));
    dataTable.Columns.Add("ExtraField3", typeof(string));

    foreach (var record in records)
    {
        dataTable.Rows.Add(record.CsvColumn1, record.CsvColumn2, record.ExtraField1, record.ExtraField2, record.ExtraField3);
    }

    await bulkCopy.WriteToServerAsync(dataTable);
}

4. 关键注意事项

  • CSV表头匹配:如果CSV表头和CsvRecord属性名不一致,可以用[Name("表头名称")]特性配置映射,比如:
    public class CsvRecord
    {
        [Name("用户ID")]
        public string UserId { get; set; }
    }
    
  • 数据类型转换:如果CSV里有数字、日期等类型,直接在CsvRecord里用对应类型即可,CsvHelper会自动处理格式转换。
  • 大文件处理:如果CSV文件很大,别一次性把所有记录读到内存,改用csv.Read()逐行读取,每积累一定数量(比如1000条)就批量插入一次,避免内存溢出:
    var batchSize = 1000;
    var batch = new List<YourSqlTableEntity>();
    while (csv.Read())
    {
        var record = csv.GetRecord<CsvRecord>();
        batch.Add(new YourSqlTableEntity { /* 映射字段 */ });
        if (batch.Count >= batchSize)
        {
            await BulkInsertToSql(batch);
            batch.Clear();
        }
    }
    // 插入剩余的记录
    if (batch.Count > 0) await BulkInsertToSql(batch);
    
  • 异常处理:记得加try-catch块,捕获解析错误、数据库连接错误等情况,返回友好的错误信息。

AngularJS端的小提醒

确保上传时把附加字段和文件一起放到FormData里:

var formData = new FormData();
formData.append('csvFile', file);
formData.append('field1', $scope.formField1);
formData.append('field2', $scope.formField2);
formData.append('field3', $scope.formField3);

Upload.upload({
    url: '/api/your-route/upload-csv',
    data: formData
}).then(function (resp) {
    console.log('上传成功:' + resp.data);
}, function (resp) {
    console.log('上传失败,状态码:' + resp.status);
});

内容的提问来源于stack exchange,提问作者B-Ray

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:20:50