【发布时间】:2011-06-03 21:44:38
【问题描述】:
有谁知道是否可以使用 Dapper 将 table-valued parameter 数据传递给存储过程?
【问题讨论】:
-
或者您可以使用 bulkinsert 到临时表 stackoverflow.com/a/9947259/37055
有谁知道是否可以使用 Dapper 将 table-valued parameter 数据传递给存储过程?
【问题讨论】:
现在(n Dapper 1.26 及更高版本)直接支持烘焙到 dapper 中的表值参数。对于存储过程,由于数据类型内置在 sproc API 中,您只需提供一个DataTable:
var data = connection.Query<SomeType>(..., new {
id=123, name="abc", values = someTable
}, ...);
对于直接命令文本,您还有另外两个选项:
使用辅助方法告诉它自定义数据类型:
var data = connection.Query<SomeType>(..., new {
id=123, name="abc", values = someTable.AsTableValuedParameter("mytype")
}, ...);
告诉数据表本身使用什么自定义数据类型:
someTable.SetTypeName("mytype");
var data = connection.Query<SomeType>(..., new {
id=123, name="abc", values = someTable
}, ...);
其中任何一个都应该可以正常工作。
【讨论】:
ExecuteReader,我得到“System.Data.DataTable 类型的成员事件不能用作参数值”。
是的,我们支持它们,但您需要编写自己的助手代码。
例如:
class IntDynamicParam : Dapper.SqlMapper.IDynamicParameters
{
IEnumerable<int> numbers;
public IntDynamicParam(IEnumerable<int> numbers)
{
this.numbers = numbers;
}
public void AddParameters(IDbCommand command)
{
var sqlCommand = (SqlCommand)command;
sqlCommand.CommandType = CommandType.StoredProcedure;
List<Microsoft.SqlServer.Server.SqlDataRecord> number_list = new List<Microsoft.SqlServer.Server.SqlDataRecord>();
// Create an SqlMetaData object that describes our table type.
Microsoft.SqlServer.Server.SqlMetaData[] tvp_definition = { new Microsoft.SqlServer.Server.SqlMetaData("n", SqlDbType.Int) };
foreach (int n in numbers)
{
// Create a new record, using the metadata array above.
Microsoft.SqlServer.Server.SqlDataRecord rec = new Microsoft.SqlServer.Server.SqlDataRecord(tvp_definition);
rec.SetInt32(0, n); // Set the value.
number_list.Add(rec); // Add it to the list.
}
// Add the table parameter.
var p = sqlCommand.Parameters.Add("@ints", SqlDbType.Structured);
p.Direction = ParameterDirection.Input;
p.TypeName = "int_list_type";
p.Value = number_list;
}
}
// SQL Server specific test to demonstrate TVP
public void TestTVP()
{
try
{
connection.Execute("CREATE TYPE int_list_type AS TABLE (n int NOT NULL PRIMARY KEY)");
connection.Execute("CREATE PROC get_ints @ints int_list_type READONLY AS select * from @ints");
var nums = connection.Query<int>("get_ints", new IntDynamicParam(new int[] { 1, 2, 3 })).ToList();
nums[0].IsEqualTo(1);
nums[1].IsEqualTo(2);
nums[2].IsEqualTo(3);
nums.Count.IsEqualTo(3);
connection.Execute("DROP PROC get_ints");
connection.Execute("DROP TYPE int_list_type");
}
}
确保正确测试表值参数的性能。当我测试它以传递 int 列表时,它比传递多个参数要慢得多。
我完全不反对在 contrib 项目中为 dapper 提供一些特定于 SQL Server 的帮助程序,但是核心 dapper 会尽可能避免添加特定于供应商的技巧。
【讨论】:
我知道这张票很旧,很旧,但想让你知道我已经发布了 Dapper.Microsoft.Sql 包,它支持通用 TVP。
https://www.nuget.org/packages/Dapper.Microsoft.Sql/
使用示例:
List<char> nums = this.connection.Query<char>(
"get_ints",
new TableValuedParameter<char>(
"@ints", "int_list_Type", new[] { 'A', 'B', 'C' })).ToList();
它基于 Dapper 测试项目的原始类。
享受吧!
【讨论】:
今天不是。我们实际上为我们厚颜无耻的“in”实现(where col in @values)调查了 table-valed-parameters,但对性能非常不满意。但是在 SPROC 的上下文中它是有意义的。
您最好的选择是log this as an issue on the project site,以便我们对其进行跟踪/优先处理。不过,这听起来像是可行的,可能类似于 DbString 或 DynamicParameters 选项。
但是今天呢?没有。
【讨论】: