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

使用MVC5+EF6+SqlBulkCopy导入Excel至SQL遇三类错误求助

解决Excel批量导入SQL时的三类错误(MVC5 + EF6 + EPPlus + SqlBulkCopy)

我来帮你逐个排查并解决这三个问题,让你的批量导入功能正常跑起来:

1. 无法将DbConnection转换为SqlConnection的问题

原因

SqlBulkCopy只接受**SqlConnection类型的连接实例,但EF的Database.Connection返回的是通用的DbConnection抽象类型,直接传递会触发类型转换错误。另外,SqlBulkCopy要求连接处于打开状态**才能工作。

解决方法

  • 把DbConnection强制转换为SqlConnection(你的EF模型是SQL Server的,所以转换是安全的)
  • 保存连接的原始状态,使用后恢复(避免破坏EF自身的连接管理逻辑)

2. SqlBulkCopy被当作命名空间使用的问题

原因

这个错误通常是因为:

  • 代码文件顶部没引用System.Data.SqlClient命名空间
  • 自定义的BulkWriter类里错误地用命名空间代替了SqlBulkCopy实例
  • 存在命名冲突(比如自定义了同名的类)

解决方法

  • 确保添加using System.Data.SqlClient;
  • 在BulkWriter中正确实例化SqlBulkCopy对象,而不是直接调用命名空间

3. ObjectReader相关问题

原因

SqlBulkCopy需要IDataReader作为数据源,我们一般用FastMember库的ObjectReader把List<T>转成IDataReader。出错大概率是:

  • 没安装FastMember NuGet包
  • 没引用FastMember命名空间
  • ObjectReader的使用语法错误

解决方法

  • 通过NuGet安装FastMember:Install-Package FastMember
  • 添加using FastMember;命名空间
  • 用ObjectReader.Create(你的列表)生成数据读取器

修正后的完整代码

下面是整合所有修复点的实现,包括补全你用到的BulkWriter类:

首先添加必要的命名空间:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Mvc;
using EPPlus;
using FastMember;

然后是修复后的BulkWriter类:

public class BulkWriter
{
    public async Task InsertAsync<T>(List<T> data, string tableName, DbConnection connection, CancellationToken cancellationToken)
    {
        // 转换为SqlConnection
        if (connection is not SqlConnection sqlConnection)
        {
            throw new ArgumentException("仅支持SQL Server连接");
        }

        // 保存连接原始状态,使用后恢复
        var wasOpen = sqlConnection.State == ConnectionState.Open;
        try
        {
            if (!wasOpen)
            {
                await sqlConnection.OpenAsync(cancellationToken);
            }

            // 用FastMember生成IDataReader
            using var reader = ObjectReader.Create(data);
            using var bulkCopy = new SqlBulkCopy(sqlConnection)
            {
                DestinationTableName = tableName,
                BatchSize = 1000 // 批量大小可根据数据量调整
            };

            await bulkCopy.WriteToServerAsync(reader, cancellationToken);
        }
        finally
        {
            // 恢复连接初始状态
            if (!wasOpen && sqlConnection.State == ConnectionState.Open)
            {
                await sqlConnection.CloseAsync();
            }
        }
    }
}

最后是你的Controller方法修正:

public async Task<ActionResult> ApplicationAsync(FormCollection formCollection)
{
    var usersList = new List<bomApplicationImportTgt>();

    if (Request != null)
    {
        HttpPostedFileBase file = Request.Files["UploadedFile"];
        if ((file != null) && (file.ContentLength > 0) && !string.IsNullOrEmpty(file.FileName))
        {
            string fileName = file.FileName;

            using (var package = new ExcelPackage(file.InputStream))
            {
                var workSheet = package.Workbook.Worksheets.First();
                var noOfRow = workSheet.Dimension.End.Row;

                for (int rowIterator = 2; rowIterator <= noOfRow; rowIterator++)
                {
                    // 这里可以添加空值容错,比如用int.TryParse代替Convert.ToInt32
                    var user = new bomApplicationImportTgt
                    {
                        date = Convert.ToDateTime(workSheet.Cells[rowIterator, 1].Value),
                        Description = workSheet.Cells[rowIterator, 2].Value?.ToString(),
                        SequenceNumber = Convert.ToInt32(workSheet.Cells[rowIterator, 3].Value),
                        PartNumber = workSheet.Cells[rowIterator, 4].Value?.ToString(),
                        PartsName = workSheet.Cells[rowIterator, 5].Value?.ToString(),
                        SP = workSheet.Cells[rowIterator, 6].Value?.ToString(),
                        INT = workSheet.Cells[rowIterator, 7].Value?.ToString(),
                        SN = workSheet.Cells[rowIterator, 8].Value?.ToString(),
                        SZ = workSheet.Cells[rowIterator, 9].Value?.ToString(),
                        C = workSheet.Cells[rowIterator, 10].Value?.ToString(),
                        E_F = workSheet.Cells[rowIterator, 11].Value?.ToString(),
                        Block = workSheet.Cells[rowIterator, 12].Value?.ToString(),
                        SEC = workSheet.Cells[rowIterator, 13].Value?.ToString(),
                        Item = workSheet.Cells[rowIterator, 14].Value?.ToString(),
                        SUF = workSheet.Cells[rowIterator, 15].Value?.ToString(),
                        Model = workSheet.Cells[rowIterator, 16].Value?.ToString(),
                        M_E_F = workSheet.Cells[rowIterator, 17].Value?.ToString(),
                        OP = workSheet.Cells[rowIterator, 18].Value?.ToString(),
                        Type = workSheet.Cells[rowIterator, 19].Value?.ToString(),
                        Quantity = workSheet.Cells[rowIterator, 20].Value?.ToString(),
                        PLGRPCD = workSheet.Cells[rowIterator, 21].Value?.ToString(),
                        PL1 = workSheet.Cells[rowIterator, 22].Value?.ToString(),
                        ATC1 = workSheet.Cells[rowIterator, 23].Value?.ToString(),
                        PL2 = workSheet.Cells[rowIterator, 24].Value?.ToString(),
                        ATC2 = workSheet.Cells[rowIterator, 25].Value?.ToString(),
                        PL3 = workSheet.Cells[rowIterator, 26].Value?.ToString(),
                        ATC3 = workSheet.Cells[rowIterator, 27].Value?.ToString(),
                        Plant = workSheet.Cells[rowIterator, 28].Value?.ToString(),
                        SHR = workSheet.Cells[rowIterator, 29].Value?.ToString(),
                        DC_Number = workSheet.Cells[rowIterator, 30].Value?.ToString(),
                        FileName = fileName
                    };
                    usersList.Add(user);
                }
            }
        }
    }

    // 只有当列表有数据时才执行批量导入
    if (usersList.Any())
    {
        using (Dev_Purchasing_New_ModelEntities excelImportDBEntities = new Dev_Purchasing_New_ModelEntities())
        {
            await new BulkWriter().InsertAsync(usersList, "bomApplicationImportTgt", excelImportDBEntities.Database.Connection, CancellationToken.None);
        }
    }

    return View("Application");
}

额外提示

  • 确保bomApplicationImportTgt实体的属性名和数据库表的列名完全一致(大小写不敏感,但匹配度越高越不容易出问题),如果不一致需要手动添加bulkCopy.ColumnMappings.Add("属性名", "列名")
  • Excel单元格空值处理可以优化,比如用int.TryParse(workSheet.Cells[rowIterator,3].Value?.ToString(), out var seqNum)然后赋值user.SequenceNumber = seqNum,避免转换异常
  • BatchSize可以根据你的数据量调整,1000-5000是比较常用的取值,平衡内存占用和导入速度

内容的提问来源于stack exchange,提问作者Minhal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:33:14