如何使用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条,逐行调用存储过程性能较低,可以使用表值参数实现单次请求批量写入,性能提升非常明显:
- 首先在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 )
- 修改存储过程接收表值参数
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
- 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
相关产品推荐
相关产品推荐

