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

如何使用Dapper将List<myobject>作为参数调用存储过程插入数据

报错原因

该错误的核心诱因是:你传入的List<Postings>中Postings类的属性和存储过程要求的7个参数不匹配。Dapper默认会将实体类的所有公共属性自动转换为存储过程的传入参数,如果你的Postings类是和表结构一一对应的,会包含Id、BankAccount、HideThisRecord三个存储过程不需要的属性,最终导致传入参数数量超出存储过程定义,触发报错。同时你当前代码里写的存储过程名spMyStoredProc和实际定义的spInsertCommonPostings不符,也需要修正。


解决方法

方法1:投影必要属性后传入(最简单通用)

不需要修改原有类和存储过程,仅需要在传参时将列表元素投影为仅包含存储过程所需7个字段的匿名对象即可,代码如下:

// 仅提取存储过程需要的属性
var execParams = MyList.Select(p => new 
{
    p.BankRegistrationNumber,
    p.BankAccountNumber,
    p.BankName,
    p.PostingAmount,
    p.PostingDate,
    p.Primo,
    p.PostingText
}).ToList();

// 调用存储过程
connection.Execute(
    sql: "bank.spInsertCommonPostings", 
    param: execParams, 
    commandType: CommandType.StoredProcedure);

该方案会自动遍历列表,每一条数据对应调用一次存储过程,完全对齐你原有逻辑需求。

方法2:显式指定参数(适配属性名不匹配场景)

如果你的实体类属性名和存储过程参数名不一致,或者需要手动控制参数类型/方向,可以用DynamicParameters显式定义参数:

var paramList = new List<DynamicParameters>();
foreach (var posting in MyList)
{
    var param = new DynamicParameters();
    param.Add("@BankRegistrationNumber", posting.BankRegistrationNumber);
    param.Add("@BankAccountNumber", posting.BankAccountNumber);
    param.Add("@BankName", posting.BankName);
    param.Add("@PostingAmount", posting.PostingAmount);
    param.Add("@PostingDate", posting.PostingDate);
    param.Add("@Primo", posting.Primo);
    param.Add("@PostingText", posting.PostingText);
    paramList.Add(param);
}

connection.Execute(
    sql: "bank.spInsertCommonPostings", 
    param: paramList, 
    commandType: CommandType.StoredProcedure);

大数据量高性能优化方案

如果待写入数据量超过1000条,逐行调用存储过程性能较低,可以使用表值参数实现单次请求批量写入,性能提升非常明显:

  1. 首先在SQL Server创建自定义表类型
CREATE TYPE [bank].[PostingsTableType] AS TABLE(
    [BankRegistrationNumber] [INT] NOT NULL,
    [BankAccountNumber] [BIGINT] NOT NULL,
    [BankName] [NVARCHAR](50) NULL,
    [PostingAmount] [DECIMAL](18, 2) NOT NULL,
    [PostingDate] [DATE] NOT NULL,
    [Primo] [CHAR](1) NULL,
    [PostingText] [NVARCHAR](100) NULL
)
  1. 修改存储过程接收表值参数
ALTER PROCEDURE [bank].[spBulkInsertCommonPostings]
    @PostingsList [bank].[PostingsTableType] READONLY
AS
BEGIN
    SET NOCOUNT ON;
    INSERT INTO bank.CommonPostingsFromBankFiles (
        BankRegistrationNumber, BankAccountNumber, BankName, 
        PostingAmount, PostingDate, Primo, PostingText
    )
    SELECT 
        p.BankRegistrationNumber, p.BankAccountNumber, p.BankName,
        p.PostingAmount, p.PostingDate, p.Primo, p.PostingText
    FROM @PostingsList p
    WHERE NOT EXISTS (
        SELECT 1 FROM bank.CommonPostingsFromBankFiles f
        WHERE f.BankRegistrationNumber = p.BankRegistrationNumber
          AND f.BankAccountNumber = p.BankAccountNumber
          AND f.BankName = p.BankName
          AND f.PostingAmount = p.PostingAmount
          AND f.PostingDate = p.PostingDate
    )
END
  1. C#调用代码
// 构造和自定义表类型结构一致的DataTable
var dt = new DataTable();
dt.Columns.Add("BankRegistrationNumber", typeof(int));
dt.Columns.Add("BankAccountNumber", typeof(long));
dt.Columns.Add("BankName", typeof(string));
dt.Columns.Add("PostingAmount", typeof(decimal));
dt.Columns.Add("PostingDate", typeof(DateTime));
dt.Columns.Add("Primo", typeof(string));
dt.Columns.Add("PostingText", typeof(string));

foreach (var posting in MyList)
{
    dt.Rows.Add(
        posting.BankRegistrationNumber,
        posting.BankAccountNumber,
        posting.BankName,
        posting.PostingAmount,
        posting.PostingDate,
        posting.Primo,
        posting.PostingText
    );
}

var param = new DynamicParameters();
param.Add("@PostingsList", dt.AsTableValuedParameter("bank.PostingsTableType"));

connection.Execute(
    sql: "bank.spBulkInsertCommonPostings",
    param: param,
    commandType: CommandType.StoredProcedure);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 00:54:06