【问题标题】:Populate C# DataTable Asynchronously异步填充 C# DataTable
【发布时间】:2017-12-19 16:26:00
【问题描述】:

我正在向我的 WebAPI 项目中使用的所有 SQL 基类添加 async 实现。我对 TAP 范式还很陌生,所以我还在学习。

我知道,感谢其他帖子,通过 Task.Run() 生成线程在 ASP.NET 上下文中没有任何性能优势。所以我对我的实现要格外小心。

我已将我的 QueryExecutor 方法更改为下面的异步实现。但无法弄清楚加载 DataTable 的最佳方式是什么。我猜我最好使用reader.ReadAsync() 来填充DataTable,但.NET 4.5 框架中似乎没有任何可用的东西。

所以我想问是否值得编写我自己的扩展方法,例如DataTable.LoadAsync(DbDataReader reader)?如果可以提供帮助,我有点不想这样做,因为它不会像托管的 .Net 代码那样万无一失。

让我知道你们的想法。

private async Task<DataTable> ExecuteQueryInternalAsync(string commandText, CommandType commandType, SqlConnection sqlConnection, SqlTransaction transaction, params SqlParameter[] parameters)
{
    using (SqlCommand cmd = new SqlCommand(commandText, sqlConnection) { CommandType = commandType, CommandTimeout = this.config.MainConnectionTimeoutInSeconds })
    {
        if (transaction != null)
            cmd.Transaction = transaction;

        if (parameters != null)
        {
            foreach (var parameter in parameters)
            {
                if (parameter != null)
                {
                    if (parameter.Value == null)
                        parameter.Value = DBNull.Value;

                    cmd.Parameters.Add(parameter);
                }
            }
        }

        if (sqlConnection.State == ConnectionState.Closed)
            await sqlConnection.OpenAsync();

        using (var reader = await cmd.ExecuteReaderAsync())
        {
            //Want to use: reader.ReadAsync()
            var tb = new DataTable();
            tb.Load(reader);
            return tb;
        }
    }
}

谢谢

【问题讨论】:

  • 只是一个侧节点:您的示例代码是托管的 .Net 代码
  • 一般来说,异步代码使用实体框架查询而不是DataTables。
  • 我确实使用 EF 6。但有时您只需要执行 SP 并将结果作为 DataTable 获取。

标签: c# .net sql-server datatable async-await


【解决方案1】:

如果想要扩展方法,可以直接写在命令上

public static class extensions
    {
         public async static Task<DataTable> ExecuteAndCreateDataTableAsync(this SqlCommand cmd)
         {
             using (var reader = await cmd.ExecuteReaderAsync().ConfigureAwait(false))
             {
                 var dataTable = reader.CreateTableSchema();
                 while (await reader.ReadAsync().ConfigureAwait(false))
                 {
                     var dataRow = dataTable.NewRow();
                     for (int i = 0; i < dataTable.Columns.Count; i++)
                     {
                         dataRow[i] = reader[i];
                     }
                     dataTable.Rows.Add(dataRow);
                 }
                 return dataTable;

             }
         }
         public static void LoadParams(this SqlCommand cmd, params SqlParameter[] parameters)
         {
             if (parameters != null)
             {
                 foreach (var parameter in parameters)
                 {
                     if (parameter != null)
                     {
                         if (parameter.Value == null)
                             parameter.Value = DBNull.Value;

                         cmd.Parameters.Add(parameter);
                     }
                 }
             }
         }


         private static DataTable CreateTableSchema(this SqlDataReader reader)
         {
             DataTable schema = reader.GetSchemaTable();
             DataTable dataTable = new DataTable();
             if (schema != null)
             {
                 foreach (DataRow drow in schema.Rows)
                 {
                     string columnName = System.Convert.ToString(drow["ColumnName"]);
                     DataColumn column = new DataColumn(columnName, (Type)(drow["DataType"]));
                     dataTable.Columns.Add(column);
                 }
             }
             return dataTable;
         }
    }

还有你的方法:

private async Task<DataTable> ExecuteQueryInternalAsync(string commandText, CommandType commandType, SqlConnection sqlConnection, SqlTransaction transaction, params SqlParameter[] parameters)
        {
            using (SqlCommand cmd = new SqlCommand(commandText, sqlConnection) { CommandType = commandType, CommandTimeout = this.config.MainConnectionTimeoutInSeconds })
            {
                if (transaction != null)
                    cmd.Transaction = transaction;

                cmd.LoadParams(parameters);

                if (sqlConnection.State == ConnectionState.Closed)
                    await sqlConnection.OpenAsync();

                var datatable =  await cmd.ExecuteAndCreateDataTableAsync();
                return datatable;
            }
        }

【讨论】:

  • 所以我的部分问题是,这样做值得吗?是否值得使用 ReadAsync() 而不是仅仅同步填充 DataTable。
  • 这只是实现。我认为 ExecuteReaderAsync 之后没有必要
猜你喜欢
  • 2018-08-11
  • 1970-01-01
  • 2013-03-05
  • 1970-01-01
  • 2017-07-26
  • 1970-01-01
  • 2010-09-20
  • 2018-10-16
  • 1970-01-01
相关资源
最近更新 更多