c# - BeginExecuteReader、EndExecuteReader 和多个结果

标签 c# .net asynchronous .net-4.5 sqldatareader

我有一个方法可以从我的数据库中异步获取结果:

internal class CommandAndCallback<TCallback, TError>
{
    public SqlCommand Sql { get; set; }
    public TCallback Callback { get; set; }
    public TError Error { get; set; }
}

public void GetResults(string param, Action<DataTable,DataTable> callback, Action<string> error, Action<string> info)
{
    var conn = new SqlConnection(_connString);
    conn.InfoMessage += delegate(object sender, SqlInfoMessageEventArgs e)
    {
        if (e.Errors.Count <= 0) return;
        foreach (SqlError message in e.Errors)
        {
            info(message.State + " " + message.Message);
        }
    };
    SqlCommand cmd = conn.CreateCommand();
    cmd.CommandTimeout = 0;
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.CommandText = @"GetData";
    cmd.Parameters.Add("@param", SqlDbType.NVarChar).Value = param;

    try
    {
        cmd.Connection.Open();
    }
    catch (Exception ex)
    {
        error(ex.ToString());
        return;
    }

    var ar = new CommandAndCallback<Action<DataTable,DataTable>, Action<string>> { Callback = callback, Error = error, Sql = cmd };
    cmd.BeginExecuteReader(Krok2_Handler, ar, CommandBehavior.CloseConnection);
}

private static void Krok2_Handler(IAsyncResult result)
{
    var ar = (CommandAndCallback<Action<DataTable,DataTable>, Action<string>>)result.AsyncState;

    if (result.IsCompleted)
    {
        try
        {
            SqlDataReader dr = ar.Sql.EndExecuteReader(result);
            var dt1 = new DataTable();
            var dt2 = new DataTable();
            dt1.Load(dr);
            if (dr.NextResult())//I can't access second table in results
            {
                dt2.Load(dr);
            }
            dr.Close();
            ar.Callback(dt1,dt2);
        }
        catch (Exception ex)
        {
            ar.Error(ex.Message);
        }
    }
    else
    {
        ar.Error("Error calling SQL");
    }
}

我这样调用它:

GetResults("Param value, Success, Error, Info);

当我的过程返回单个结果时一切正常,但是当我添加第二个选择时我的数据读取器没有得到它们,可能是因为当我调用 EndExecuteReader 时连接正在关闭。

如何修改我的代码以支持多个结果,以便将它们传递给我的回调方法?

最佳答案

我已经测试过了,我认为问题出在这里:

dt1.Load(dr);
if (dr.NextResult())//I can't access second table in results
{
  dt2.Load(dr);
}

据我所知,对 Load 的调用会自动将 SqlDataReader 推进到下一个记录集,因此您对 dr.NextResult() 的调用将返回 false。

如果你只是这样做,我想你会发现它有用,它对我有用:

dt1.Load(dr);
dt2.Load(dr);

编辑: 我刚刚检查了 DataTable.Load 的来源,它确实为您调用了 NextResult 方法:

if (!reader.IsClosed && !reader.NextResult())
{
    reader.Close();
}

编辑2 当循环 SqlDataReader 你应该使用这个:

if (result.IsCompleted)
{
    try
    {
        List<string> table1 = new List<string>();
        List<string> table2 = new List<string>();
        SqlDataReader dr = ar.Sql.EndExecuteReader(result);

        while (dr.Read())
        {
            table1.Add(dr[0].ToString());//get data from first table
        }

        if (dr.NextResult())//second table
        {
            while (dr.Read())
            {
                table2.Add(dr[0].ToString()); //get data from second table
            }
        }

        dr.Close();
        ar.Callback(table1 ,table2);
    }
    catch (Exception ex)
    {
        ar.Error(ex.Message);
    }
}

关于c# - BeginExecuteReader、EndExecuteReader 和多个结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28251057/

相关文章:

c# - 使用 Exchange 服务和 OAuth 订阅推送通知时出现 401 Unauthorized

.net - Microsoft.Extensions.Caching 和 System.Runtime.Caching 之间有什么区别?

java - ActiveMQ:在没有代理的情况下启动消费者

.net - 2015 年在 Linux 中运行 .NET 应用程序

javascript - 带有 C# 后端的 Electron GUI

C# OutOfMemory、映射内存文件或临时数据库

c# - DataGridview 搜索 : show only searchresult and hide other rows?

android - 我的 AsyncTask 没有被取消 android

javascript - Promise 链拆分以执行多个异步任务

c# - 生成 CPU 缓存未命中时的性能