BeginExecuteReader、EndExecuteReader 和多个结果

BeginExecuteReader, EndExecuteReader and multiple results

我有从我的数据库异步获取结果的方法:

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

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

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

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

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

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

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

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

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

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

EDIT2 当循环 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);
    }
}