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



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

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

调用类的方法示例:

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

不要在另一个线程上执行数据库查询,而是使用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 .数据库操作不执行任何需要在另一个线程上执行的"繁重"操作。数据库操作仅发送命令并等待响应 - 因此仅使用另一个线程进行等待是浪费资源。
而是使用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;
    }
}

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

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

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应该没有任何问题。

谢谢你@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;
        }

谢谢@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;
                }));
            });
        }

最新更新