TPL 任务和存储过程

发布于 2024-11-28 17:02:48 字数 2142 浏览 0 评论 0原文

我想知道是否可以通过使用任务异步调用具有相同参数的多个不同存储过程,然后等待所有结果返回。

我有以下问题:

private Task<DataTable> DataBaseCall(string procedureName, params Pair[] where)
    {
        DataTable data = new DataTable();
        SqlConnection connection = new SqlConnection(connStr);

        SqlCommand command = new SqlCommand(procedureName, connection);
        connection.Open();

        for (int i = 0; i < where.Length; i++)
        {
            command.Parameters.Add(where[i].First.ToString(), where[i].Second.ToString());
        }

        var readerTask = Task<SqlDataReader>.Factory.FromAsync(command.BeginExecuteReader, command.EndExecuteReader, null);
        return readerTask.ContinueWith(t =>
            {
                var reader = t.Result;
                try
                {
                    reader.Read();
                    data.Load(reader);
                    return data;
                }
                finally
                {
                    reader.Dispose();
                    command.Connection.Close();
                    command.Connection.Dispose();
                    command.Dispose();
                }
            });
    }

我打电话时提出:

private void SetReportVariables(string reportName, string[] storedProcedureName, string _clientGroup, string _clientCode, string _finYear, string _period)
    {
       Task[] tasks = new Task[storedProcedureName.Length];

        for (int i = 0; i < storedProcedureName.Length; i++)
        {
            List<Pair> parameters = new List<Pair>();
            parameters.Add(new Pair("@ClientGroup", _clientGroup));
            parameters.Add(new Pair("@ClientCode", _clientCode));
            parameters.Add(new Pair("@FinYear", _finYear));

            tasks[i] = DataBaseCall(storedProcedureName[i], parameters.ToArray());
        }
        Task.WaitAll(tasks);

        ...........Do something with the DataTables.........
    }

我有三个问题。

  1. 谁能告诉我这是否是一个好方法?
  2. 任何想法都是为什么我的 _finYear 变量有时似乎被省略,这会导致错误。
  3. 我可以从任务中返回数据表吗?

谢谢迈克

I was wondering if it is possible to call a number of different stored procedures with the same parameters asynchronously by using tasks and then waiting for all the results to return.

I have the following:

private Task<DataTable> DataBaseCall(string procedureName, params Pair[] where)
    {
        DataTable data = new DataTable();
        SqlConnection connection = new SqlConnection(connStr);

        SqlCommand command = new SqlCommand(procedureName, connection);
        connection.Open();

        for (int i = 0; i < where.Length; i++)
        {
            command.Parameters.Add(where[i].First.ToString(), where[i].Second.ToString());
        }

        var readerTask = Task<SqlDataReader>.Factory.FromAsync(command.BeginExecuteReader, command.EndExecuteReader, null);
        return readerTask.ContinueWith(t =>
            {
                var reader = t.Result;
                try
                {
                    reader.Read();
                    data.Load(reader);
                    return data;
                }
                finally
                {
                    reader.Dispose();
                    command.Connection.Close();
                    command.Connection.Dispose();
                    command.Dispose();
                }
            });
    }

Which I call with:

private void SetReportVariables(string reportName, string[] storedProcedureName, string _clientGroup, string _clientCode, string _finYear, string _period)
    {
       Task[] tasks = new Task[storedProcedureName.Length];

        for (int i = 0; i < storedProcedureName.Length; i++)
        {
            List<Pair> parameters = new List<Pair>();
            parameters.Add(new Pair("@ClientGroup", _clientGroup));
            parameters.Add(new Pair("@ClientCode", _clientCode));
            parameters.Add(new Pair("@FinYear", _finYear));

            tasks[i] = DataBaseCall(storedProcedureName[i], parameters.ToArray());
        }
        Task.WaitAll(tasks);

        ...........Do something with the DataTables.........
    }

I have three questions.

  1. Can anyone tell me if this is a good way to do this?
  2. Any idea's why my _finYear variable seems sometimes be omitted, which causes an error.
  3. Can I return the datatable from the task?

Thanks

Mike

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

你与清晨阳光 2024-12-05 17:02:48
  1. 这种方法没有什么根本性的错误。
  2. 您没有在代码中显示 _finYear 来自何处,但根据您显示的代码,我看不出有任何理由不能将其正确传递到存储过程。
  3. 当然你可以像这样返回DataTable。从多个线程并发访问并不安全,但可以跨线程传递,没有问题。

代码中唯一的小错误是,您应该在继续处理逻辑中再添加一个 try/finally,因为如果对 t.Result 的异步调用出现问题,t.Result 可能会抛出异常。 code>Begin/EndExecuteReader 这将使您无法处理命令和连接。所以这样会更好:

readerTask.ContinueWith(t =>            
{                
    try
    {
        var reader = t.Result;                

        try                
        {                    
            reader.Read();
            data.Load(reader);

            return data;
        }
        finally
        {                    
            reader.Dispose();
        }            
    }
    finally
    {
        command.Connection.Close();
        command.Connection.Dispose();
        command.Dispose();                
    }
});
  1. There's nothing fundamentally wrong with this approach.
  2. You don't show where _finYear comes from in your code, but based on the code that you do show I don't see any reason for it to not be passed through correctly to the sproc.
  3. Sure you can return the DataTable like that. It's not safe to access concurrently from multiple threads, but it can be handed across threads no problem.

The only minor bug in your code is that you should have another try/finally in your continuation handling logic because it's possible for t.Result to throw an exception if there was a problem with the async call to Begin/EndExecuteReader and that would leave you not disposing of the command and connection. So this would be better:

readerTask.ContinueWith(t =>            
{                
    try
    {
        var reader = t.Result;                

        try                
        {                    
            reader.Read();
            data.Load(reader);

            return data;
        }
        finally
        {                    
            reader.Dispose();
        }            
    }
    finally
    {
        command.Connection.Close();
        command.Connection.Dispose();
        command.Dispose();                
    }
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文