有谁知道是否可以使用 Dapper 将表值参数数据传递给存储过程?
4 回答
现在(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 }, ...);
这些中的任何一个都应该可以正常工作。
是的,我们支持它们,但您需要编写自己的助手代码。
例如:
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
)调查了表值参数,但对性能非常不满意。然而,在 SPROC 的上下文中,这是有道理的。
您最好的选择是将其作为问题记录在项目站点上,以便我们对其进行跟踪/优先排序。不过,这听起来像是可行的,可能类似于 DbString 或 DynamicParameters 选项。
但今天?不。