Dapper是否支持SQL 2008表值参数?


Answers:


91

现在(对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
    }, ...);        
    

这些中的任何一个都可以正常工作。


在无法使用Dapper添加TVP的情况下,如果我需要添加非输入参数,并且在使用动态参数的情况下无法添加TVP,请检查我的问题@ stackoverflow.com/questions/33087629/ …
Mrinal Kamboj 2015年

9
ah,没有IEnumerable转换?
nuzzolilo 2015年

通过ExecuteReader,我得到“ System.Data.DataTable类型的成员事件不能用作参数值”。
伊恩·沃伯顿

28

是的,我们支持他们,但是您将需要编写自己的助手。

例如:

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项目中使用一些SQL Server专用的dapper帮助程序,但是核心dapper避免在可能的地方添加特定于供应商的技巧。


1
实际上,使用TVP比“ @values中的col”要慢。我如何使用列表支持功能(Dapper允许您传递IEnumerable <int>并将自动参数化查询)将整数列表传递给StoredProcedure?
卡洛斯·门德斯

这是批处理速度快于sps的疯狂边缘情况之一,dapper用于列表支持的技术与存储的
Sam Saffron

你能更新吗?我不能完全确定是否可以忽略较新版本的Dapper中的identity参数。
克里斯·普弗

该代码将按原样工作还是需要将IEnumerable <int>集合转换为DataTable以用作TVP
Mrinal Kamboj 2015年

11

我知道这张票是旧的,很旧,但是想让您知道我已经发布了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测试项目中的原始类。

请享用!


我试图了解如何将TVP与其他典型类型的参数一起作为参数。怎么做?
2014年

我还没有实现这一部分。
Darek 2014年

5

今天不是。实际上,我们调查了表值参数以实现我们的厚颜无耻的“实现”(where col in @values),但对性能没有任何印象。但是,在SPROC的上下文中,这是有道理的。

最好的选择是将此问题记录在项目站点上,以便我们跟踪/确定其优先级。听起来有些事情是可行的,但可能类似于DbString或DynamicParameters选项。

但今天?没有。


2
更正,我们对此提供了支持……您只需要自己编写一下即可:)
Sam Saffron
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.