Чи підтримує Dapper табличні параметри SQL 2008?


78

Хтось знає, чи можна передавати дані параметрів, що мають значення таблиці, до збереженої процедури за допомогою Dapper?


1
Як альтернативи ви можете використовувати bulkinsert для температури столу stackoverflow.com/a/9947259/37055
Кріс Marisic

Відповіді:


91

Зараз існує (n Dapper 1.26 і вище) пряма підтримка табличних параметрів, запечених у dapper. У випадку збережених процедур, оскільки тип даних вбудований в API sproc, все, що вам потрібно зробити, це надати 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
    }, ...);        
    

Будь-яка з них повинна працювати нормально.


Випадок, коли я не можу додати TVP за допомогою Dapper, якщо мені потрібно додати невхідний параметр, а також, використовуючи динамічні параметри, я не можу додати TVP, перевірте моє запитання @ stackoverflow.com/questions/33087629/ …
Мріналь Камбой

9
Бах, немає I незліченної конверсії?
nuzzolilo

З ExecuteReader, я отримую, "Події-члени типу System.Data.DataTable не можуть використовуватися як значення параметра".
Ian Warburton

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 відбувається повільніше, ніж "where col in @values". Як я можу використовувати функцію підтримки списку (Dapper дозволяє вам передати IEnumerable <int> і автоматично параметризує ваш запит) для передачі списку ints до StoredProcedure?
Карлос Мендес,

Це один з тих божевільних випадків, коли партії швидші, ніж sps, техніка, яку використовує dapper для підтримки списків, не сумісна із збереженими процесами
Сем Саффрон,

Чи можете ви оновити це? Я не можу зрозуміти, чи нормально ігнорувати параметр ідентичності в нових версіях Dapper.
Chris Pfohl

Чи буде цей код працювати як є, або йому буде потрібно IEnumerable <int> колекція для перетворення в DataTable для використання як TVP
Mrinal Kamboj

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 як параметр поряд з іншими типовими параметрами. Як це робиться?
Сніжне

Я ще не реалізував цю частину.
Дарек

5

сьогодні це не так. Ми фактично досліджували таблично-valed-параметри для нашої нахабної реалізації "in" ( where col in @values), але нас це не вразило. Однак у контексті SPROC це має сенс.

Найкраще - зареєструвати це як випуск на сайті проекту щоб ми могли відстежувати / розставляти пріоритети. Здається, щось буде здійсненно, однак, можливо, подібне до параметрів DbString або DynamicParameters.

Але сьогодні? Ні.


2
виправлення, ми начебто підтримуємо це ... вам просто потрібно його кодувати самостійно :)
Сем Саффрон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.