Какова наилучшая практика для асинхронного заполнения DataSet или DataTable в ASP.NET?

Учитывая следующий код, у меня есть несколько вопросов о лучших практиках:

string connectionString = @"Server=(local)\sqlexpress; Database=master; Integrated Security=true;";

using (SqlConnection connection = new SqlConnection(connectionString))
{
    using (SqlDataAdapter dataAdapter = new SqlDataAdapter("select * from information_schema.columns", connection))
    {
        await connection.OpenAsync();

        DataTable dataTable = new DataTable();
        await Task.Run(() => dataAdapter.Fill(dataTable));
        return dataTable;
    }
}

Я видел несколько примеров, которые переносят весь блок кода в вызов Task.Run(), но я не уверен, что это лучше, чем вызов Task.Run() только для метода DataAdapter.Fill(), который чувствует себя более гибким и конкретным (только используя ожидание асинхронных задач).

Является ли метод вызова Task.Run() метода Fill() лучше, чем обертывание всего кода кода?

Есть ли какие-либо негативные побочные эффекты для вызова Fill() в Task.Run()? Я думаю о чем-то вроде потери стека вызовов и/или информации об исключении, если Fill() имеет ошибку.

Есть ли лучший способ написать это в ASP.NET?

Ответ 1

В ASP.NET почти никогда не помогает использовать Task.Run. Что именно это улучшило бы? Он вводит только служебные данные.

Тем не менее, Fill выполнит IO (сбрасывает устройство чтения данных), поэтому вы можете назвать его асинхронным. К сожалению, нет асинхронной версии этого метода.

Если вы настаиваете на использовании async IO (который сомнительно для доступа к базе данных), вам нужно найти альтернативу. Возможно, вам может помочь async Entity Framework или необработанный ADO.NET.

Ответ 2

Вы пытались использовать DataReader и новый ExecuteReaderAsync? Я помню, что SqlDataAdapter уже использует DataReader внутри без async. Вы также можете пропустить, используя DataTable, если возможно, сократить некоторые накладные расходы.

Для небольших наборов результатов, которые очень редко меняют такие столбцы схемы запроса, я мог бы просто кэшировать его на веб-сервере одним из многих способов. Heck, для изменений схемы вы даже можете создать простой триггер DDL для обновления таблицы с одной строкой с полем временной метки, чтобы вы знали, что было сделано изменение, а затем запускать запрос, когда это необходимо. Другой вариант - CHECKSUM_AGG для таблиц, отличных от таблиц схем.