5

我有一个 WPF 应用程序,用户在某些文本框中输入数据库信息。一旦用户单击“连接”,就会根据用户输入的内容创建连接字符串并建立连接。我注意到如果用户输入任何错误的信息,应用程序将挂起,直到连接超时。通过挂起,我的意思是用户根本无法与应用程序的其余部分进行交互。

我的目标是在测试连接字符串时保持应用程序响应。

我认为将此工作流程放在不同的线程上是一个很好的解决方案。我的想法是在线程运行时禁用任何可能需要数据库连接的东西。一旦线程返回(并已确认连接字符串有效),我将重新启用所有内容。否则,请禁用所有内容。

但是,Thread当线程完成时,该类没有事件通知(或者至少我不知道)。

我也和BackgroundWorker班一起工作过。这效果更好。但是,当RunWorkerCompletedEventHandler事件被触发并且连接字符串无效时,我得到以下异常:

调用线程无法访问此对象,因为不同的线程拥有它。

这可能是因为触发完成的事件处理程序时连接仍未超时。

有没有人有任何想法,或者我不应该尝试多线程连接到数据库?

我正在做的代码大纲:

private void bw_DoWork(object sender, DoWorkEventArgs e)
{
    dbTool = new DBTool();
    // Create the connection string
    e.Result = dbTool.connectToDB(); // connectToDB() returns a bool (true if connection established)
}

private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // connectToDB() returns a bool (true if connection established)
    if(e.Result == true)  // Trying to read e.Result here throws the exception
    {
        // e.Error and e.Cancel should be checked first
        // However, I would like the thread to finish before
        // this event is fired
    }
    if (e.Error != null)
    {
        Console.WriteLine(e.Error.Message);
    }
}
4

4 回答 4

3

不要将DbConnection对象保存在单个全局变量中并在线程之间共享。

.NET 环境将自动汇集您的连接并共享它们,因此调用new DbConnection()速度非常快。

您应该将连接字符串保存在全局变量中,然后根据需要在每个线程上创建连接。

编辑:原始发帖人实际上可能想要在测试连接字符串时如何保持 WinForms 应用程序响应的想法。在这种情况下,您希望生成一个不同的线程来测试连接。从“连接测试线程”,您可以按照以下模式更新 UI -如何从 C# 中的另一个线程更新 GUI?

public void TestConnectionThread(String connstr_to_test)
{
    // Notify the user that we're doing our test
    string message = "Testing...";
    lblTestResultMessage.SetPropertyThreadSafe(() => lblTestResultMessage.Text, message);

    try {
        dbTool = new DBTool();
        message = dbTool.connectToDB();

    // If something failed, show a useful debugging message
    } catch (Exception ex) {
        message = ex.ToString();
    }

    // Use a lambda expression to communicate results to the user safely
    lblTestResultMessage.SetPropertyThreadSafe(() => lblTestResultMessage.Text, message);
}
于 2012-07-25T21:10:07.310 回答
0

DBConnection 的文档中

此类型的任何公共静态(在 Visual Basic 中为 Shared)成员都是线程安全的。不保证任何实例成员都是线程安全的。

换句话说,不同的线程不应该共享一个数据库连接,因为不能安全地共享实例。正如 Ted Spence 所建议的那样,您应该只在需要它们时创建连接(以及.Dispose()在完成它们时创建它们)。.NET 有一个内置的连接池机制,可以很好地确保在可能的情况下重用连接,但是保持连接的时间超过绝对必要的时间可能会干扰其执行此操作的能力。

于 2012-07-25T21:15:27.357 回答
0

尝试

dbtool tool = e.result as dbtool;

如果您在 dbTool 中有一个变量在查询完成时设置为 true 或 false,那么您应该可以调用

tool.variable = true/false
于 2012-07-25T21:28:00.643 回答
0

谢谢大家的意见。

我能够想出一个解决方案。在遇到Working With The WPF Dispatcher之后。我确定你可以获得UI线程的Dispatcher对象:

//...

dbTool = new DBTool();
// Initialize the connection string
// Disable some UI
Thread thread = new Thread(new ThreadStart(
        delegate()
        {
            dbTool.connectToDB();
            UIControl.Dispatcher.BeginInvoke(
              new Action(
                  update
            ));
        }
));
thread.Start();

//.....

void update()
{
    if (dbTool.validString)     // If the connection string was valid
    {
        // Re-enable controls
    }
    else     // Invalid connection string
    {
        // Keep controls disabled if no connection could be created
    }
}

这确实会在不同的线程上测试连接字符串,让应用程序的其余部分响应。

于 2012-07-26T19:13:54.100 回答