C#从带引用的线程获取数据表返回

时间:2017-02-14 10:01:34

标签: c# multithreading class datatable

我有一个方法可以从带有引用的类调用另一个方法,而这些引用又返回一个数据表。

我正在尝试在一个线程中运行该查询,现在在一个线程中运行查询本身很容易,但是如何让它从线程中返回数据表呢?

调用类的方法示例:

private void loadCombo(string sqlComand, string value, ComboBox loadBox)
        {           
            DataTable dt = new DataTable();

            //Thread thread = new Thread(() => sqlScript.loadCombo(sqlComand, value, loadBox));
            //thread.start();

            dt = sqlScript.loadCombo(sqlComand, value, loadBox);
            loadBox.ValueMember = value;
            loadBox.DataSource = dt;
            loadBox.Refresh();
        }

4 个答案:

答案 0 :(得分:0)

这听起来像一个简单的问题。

您可以使用Task(以及async/await,但这可能是可选的,通常用于禁用/启用相应按钮以防止多个执行)在事件处理程序中执行长时间运行的代码而不阻塞UI。您仍然需要调用访问UI元素:

async void loadCombo(string sqlComand, string value, ComboBox loadBox)
{
    // disable button

    await Task.Run(() =>
    {
        var dt = sqlScript.loadCombo(sqlComand, value, loadBox);
        Invoke((Action)(() =>
        {
            loadBox.ValueMember = value; // is it out parameter? anyway, copying your code
            loadBox.DataSource = dt;
            loadBox.Refresh();
        }));
    }

    // enable button
}

创建并从另一个线程传递DataTable不应该有任何问题。

答案 1 :(得分:0)

不使用async-await方法在另一个线程上执行数据库查询,而是在一个线程上执行,不会阻止UI。

为此你需要分开"数据查询"操作和ComboBox设置

public class SqlScript
{
    public async Task<DataTable> LoadDataAsync(string command, object value)
    {
        // Load data asynchronously by using ..Async methods
    }
}

private async Task loadComboAsync(string sqlComand, string value, ComboBox loadBox)
{           
    var data = await sqlScript.LoadDataAsync(sqlComand, value);

    loadBox.ValueMember = columnNameWhichRepresentValue;
    loadBox.DataSource = data;
}

你不需要调用loadBox.Refresh方法,设置新的数据源无论如何都会这样做。

请勿使用Task.Run。数据库操作什么都不做&#34;沉重的&#34;需要在另一个线程上执行。数据库操作只发送命令并等待响应 - 因此仅使用另一个线程进行等待是浪费资源 而是使用SqlConnection.OpenAsyncSqlCommand.ExecuteReaderAsync方法

public async Task<DataTable> loadCombo(string sqlCommand, string value)
{
    var yourConnectionString = "DataSource=...";
    using (var connection = new SqlConnection(yourConnectionString))
    using (var command = new SqlCommand(sqlCommand, connection))
    {
        await connection.OpenAsync();
        var reader = await command.ExecuteReaderAsync();

        var data = new DataTable();
        data.Load(reader);
        return data;
    }
}

答案 2 :(得分:0)

谢谢@Sinatr和@Fabio,我测试了你的答案的组合,下面似乎给了我最快的回报时间。

主表单方法调用:

private async Task loadCombo(string sqlCommand, string value, ComboBox loadBox)
        {   
            var data = await sqlScript.loadCombo(sqlCommand, value);
            loadBox.ValueMember = value;
            loadBox.DataSource = data;
        }

sqlScript类方法:

public async Task<DataTable> loadCombo(string sqlCommand, string value)
        {
            SqlConnection myConn;
            SqlCommand myCmd = default(SqlCommand);
            SqlDataReader oResult;
            DataTable dt = new DataTable();

            await Task.Run(() =>
            {

                using (myConn = new SqlConnection("Data Source=" + frmMain.sqlServer + ";" + "Initial Catalog=" + frmMain.sqlData + ";User Id=" + frmMain.sqlUser + ";Password=" + frmMain.sqlPwd + ";"))
                {
                    try
                    {
                        myConn.Open();

                        if (myConn.State == ConnectionState.Open)
                        {
                            myCmd = new SqlCommand((sqlCommand), myConn);
                            oResult = myCmd.ExecuteReader();
                            dt.Load(oResult);
                            myConn.Close();
                        }
                        else
                        {

                        }
                    }
                    catch (Exception err)
                    {
                        using (StreamWriter w = File.AppendText("ErrorLog.log"))
                        {
                            frmMain.Log("sqlScripts.loadCombo: " + err.Message, w);
                        }
                    }//End Try
                }//End using
            });
            return dt;
        }

答案 3 :(得分:-1)

谢谢@Sinatr,我只需要稍微调整你的答案,下面的代码似乎有效。

private async void loadCombo(string sqlCommand, string value, ComboBox loadBox)
        {
            await Task.Run(() =>
            {
                var dt = sqlScript.loadCombo(sqlCommand, value, loadBox);
                Invoke((Action)(() =>
                {
                    loadBox.ValueMember = value;
                    loadBox.DataSource = dt;
                }));
            });
        }