Поддерживает ли Dapper табличные параметры SQL 2008?

Кто-нибудь знает, можно ли передать данные табличного параметра в хранимую процедуру с помощью Dapper?


person Carlos Mendes    schedule 03.06.2011    source источник
comment
В качестве альтернативы вы можете использовать массовую вставку во временную таблицу stackoverflow.com/a/9947259/37055.   -  person Chris Marisic    schedule 26.02.2015


Ответы (4)


Теперь (в 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
    }, ...);        
    

Любой из них должен работать нормально.

person Marc Gravell    schedule 08.07.2014
comment
Случай, когда я не могу добавить TVP с помощью Dapper, если мне нужно добавить не входной параметр вместе с использованием динамических параметров, я не могу добавить TVP, пожалуйста, проверьте мой вопрос @ stackoverflow.com/questions/33087629/ - person Mrinal Kamboj; 15.10.2015
comment
Ба, нет преобразования IEnumerable? - person nuzzolilo; 24.10.2015
comment
С ExecuteReader я получаю: события-члены типа System.Data.DataTable нельзя использовать в качестве значения параметра. - person Ian Warburton; 07.03.2018

Да, мы поддерживаем их, но вам нужно будет написать свои собственные помощники.

Например:

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");

    }
}

Убедитесь, что вы правильно тестируете производительность для табличных параметров. Когда я тестировал это для передачи списков целых чисел, это было значительно медленнее, чем передача нескольких параметров.

Я совершенно не против того, чтобы в проекте contrib были некоторые специфичные для SQL Server помощники для dapper, однако основной dapper избегает добавления конкретных трюков поставщика, где это возможно.

person Sam Saffron    schedule 06.06.2011
comment
На самом деле использование TVP медленнее, чем where col в @values. Как я могу использовать функцию поддержки списков (Dapper позволяет вам передавать IEnumerable‹int› и будет автоматически параметризовать ваш запрос) для передачи списка целых чисел в StoredProcedure? - person Carlos Mendes; 06.07.2011
comment
Это один из тех сумасшедших крайних случаев, когда пакеты выполняются быстрее, чем sps, метод, который Dapper использует для поддержки списков, несовместим с хранимыми процессами. - person Sam Saffron; 07.07.2011
comment
Можете ли вы обновить это? Я не могу понять, нормально ли игнорировать параметр identity в более новых версиях Dapper. - person Chris Pfohl; 07.07.2014
comment
Будет ли этот код работать как есть, или ему потребуется коллекция IEnumerable‹int› для преобразования в DataTable для использования в качестве TVP? - person Mrinal Kamboj; 15.10.2015


сегодня это не так. На самом деле мы исследовали table-valed-parameters для нашей дерзкой "внутренней" реализации (where col in @values), но нас очень не впечатлила производительность. Однако в контексте SPROC это имеет смысл.

Лучше всего зарегистрировать это как проблему на сайте проекта, чтобы мы могли отслеживать /отдать приоритет этому. Похоже, что-то будет выполнимо, вероятно, похожее на параметры DbString или DynamicParameters.

Но сегодня? Нет.

person Marc Gravell    schedule 04.06.2011
comment
исправление, мы как бы поддерживаем его ... вам просто нужно закодировать его самостоятельно :) - person Sam Saffron; 06.06.2011