Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c#Win表单-CLR无法从COM上下文转换_C#_.net_Sql Server_Multithreading_C# 3.0 - Fatal编程技术网

c#Win表单-CLR无法从COM上下文转换

c#Win表单-CLR无法从COM上下文转换,c#,.net,sql-server,multithreading,c#-3.0,C#,.net,Sql Server,Multithreading,C# 3.0,SQL版本:SQL Server 2008 R2标准版 应用程序:.Net 3.5(Windows窗体) 这是我在运行代码后收到的错误 CLR已经60秒无法从COM上下文0xe88270转换到COM上下文0xe88328。拥有目标上下文/单元的线程很可能正在执行非泵送等待或在不泵送Windows消息的情况下处理长时间运行的操作。这种情况通常会对性能产生负面影响,甚至可能导致应用程序变得无响应或内存使用量随时间不断累积。为避免此问题,所有单线程单元(STA)线程都应使用泵送等待原语(如CoWait

SQL版本:SQL Server 2008 R2标准版
应用程序:.Net 3.5(Windows窗体)

这是我在运行代码后收到的错误

CLR已经60秒无法从COM上下文0xe88270转换到COM上下文0xe88328。拥有目标上下文/单元的线程很可能正在执行非泵送等待或在不泵送Windows消息的情况下处理长时间运行的操作。这种情况通常会对性能产生负面影响,甚至可能导致应用程序变得无响应或内存使用量随时间不断累积。为避免此问题,所有单线程单元(STA)线程都应使用泵送等待原语(如CoWaitForMultipleHandles),并在长时间运行操作期间定期泵送消息

以下代码有时会产生上述错误。很可能在插入24000多条记录后,会出现错误

准则的目标
编写代码是为了插入虚拟条目来测试我的应用程序

Random rnd = new Random();

string Data = "";

for (int i = 0; i < 2000000; i++)
{
      Data = "Insert Into Table1(Field1)values('" + rnd.Next(0, 200000000) + "');" + Environment.NewLine +
             "Insert Into Table1(Field1)values('" + rnd.Next(0, 200000000) + "');" + Environment.NewLine +
             "Insert Into Table1(Field1)values('" + rnd.Next(0, 200000000) + "');" + Environment.NewLine +
             "Insert Into Table1(Field1)values('" + rnd.Next(0, 200000000) + "');" + Environment.NewLine +
             "Insert Into Table1(Field1)values('" + rnd.Next(0, 200000000) + "');" + Environment.NewLine +
             "Insert Into Table1(Field1)values('" + rnd.Next(0, 200000000) + "');";
      ExecuteQuery(Data);//Error is displayed here
}
注意:-我在查询中编写了多个完全相同的insert语句,因为这将减少SQL必须处理的查询数量

问题
如何优化代码以防止错误发生

“CLR已经60秒无法从COM上下文…转换到COM上下文…了。拥有目标上下文/单元的线程很可能正在进行非泵送等待,或者在不泵送Windows消息的情况下处理长时间运行的操作。”

您的问题并不完全清楚您的代码是如何详细工作的,因此我将假设您的应用程序不是多线程的,即执行2×600万数据库
INSERT
s的循环在应用程序的主(UI)线程上运行。这可能需要一段时间(>60秒),因此您的UI在此期间将冻结(即使其无响应)。这是因为当您的(阻塞)循环仍在运行时,Windows窗体永远没有机会运行并对用户输入作出反应。我打赌这就是你所引用的警告的原因

请改用参数化SQL命令。 您可以做的第一件简单的事情是将
SqlCommand
转换为参数化的命令。然后,您将发出具有相同SQL文本的命令;只有单独提供的参数会有所不同:

private void InsertRandomNumbers(int[] randomNumbers)
{
    const string commandText = "INSERT INTO dbo.Table1 (Field1) VALUES (@field1);"
    using (var connection = new SqlConnection(connectionString)
    using (var command = new SqlCommand(commandText, connection))
    {
        var field1Parameter = new SqlDataParameter("@field1", SqlDbType.Int);
        command.Parameters.Add(field1Parameter);
        connection.Open();
        foreach (int randomNumber in randomNumbers)
        {
            field1Parameter.Value = randomNumber;
            /* int rowsAffected = */ command.ExecuteNonQuery();
        }
        connection.Close();
    }
}
注意
commandText
是如何定义为常量的。这很好地表明,SQL Server也会将其识别为始终相同的命令—对于参数化命令,实际参数值是单独提供的—SQL Server只会编译和优化语句一次(并将编译后的语句放入其缓存中,以便随后可以重用)而不是一次又一次地做同样的事情。仅此一项就可以节省大量时间

长时间运行的操作应该是异步的,这样您的UI就不会冻结。 您可以做的另一件事是将数据库代码转移到后台线程,这样应用程序的UI就不会冻结

假设数据库
INSERT
循环当前由按钮
doWorkButton
触发。因此,for的
循环位于按钮
Click
事件处理程序中:

private void doWorkButton_Click(object sender, EventArgs e)
{
    …
    for (i = 0; i < 2000000; i++)
    {
        Data = …
        ExecuteQuery(Data);
        // note: I leave it as an exercise to you to combine the
        // above suggestion (parameterized queries) with this one.
    }
}
就这样。现在我们需要修改handler方法,使其也是异步的:

private async void doWorkButton_Click(object sender, EventArgs e)
{
    try
    {
        …
        for (i = 0; i < 2000000; i++) { … }
        {
            Data = …
            await ExecuteNonQueryAsync(Data);
        }
    }
    catch
    {
        … // do not let any exceptions escape this handler method
    }
}

我现在不能测试,但我希望这能让你开始。如果您想进一步改进基于
SqlBulkCopy
的解决方案,我建议您创建一个
IDataReader
的自定义实现,该实现动态创建包含随机数据的“行”,然后将该行的实例传递给
SqlBulkCopy
,而不是预填充的数据表。这意味着您不必在内存中保存一个庞大的数据表,而是一次只保留一行数据。

使用后台线程,在SQL查询中执行所有这些操作,不在c#code@viveknuna我希望它能尽快工作,我不介意在屏幕前等待,这就是为什么我使用主线程来做这件事。尝试在运行执行计划时在sql server中运行查询,查看您的查询占用的时间不要太多使用索引,检查是否有锁可以使用SqlBulkCopy
private async Task ExecuteNonQueryAsync(string commandText)
{
    using (var connection = new SqlConnection(connectionString)
    using (var command = new SqlCommand(commandText, connection))
    {
        connection.Open();
        /* int rowsAffected = */ await command.ExecuteNonQueryAsync();
        connection.Close();
    }
}
private async void doWorkButton_Click(object sender, EventArgs e)
{
    try
    {
        …
        for (i = 0; i < 2000000; i++) { … }
        {
            Data = …
            await ExecuteNonQueryAsync(Data);
        }
    }
    catch
    {
        … // do not let any exceptions escape this handler method
    }
}
private async void doWorkButton_Click(object sender, EventArgs e)
{
    // Prepare the data to be loaded into your database table.
    // Note, this could be done more efficiently.
    var dataTable = new DataTable();
    {
        dataTable.Columns.Add("Field1", typeof(int));
        var rnd = new Random();
        for (int i = 0; i < 12000000; ++i)
        {
            dataTable.Rows.Add(rnd.Next(0, 2000000));
        }
    }

    using (var connection = new SqlConnection(connectionString))
    using (var bulkCopy = new SqlBulkCopy(connection))
    {
        bulkCopy.DestinationTableName = "dbo.Table1";
        try
        {
            // This will perform a bulk insert into the table
            // mentioned above, using the data passed in as a parameter.
            await bulkCopy.WriteToServerAsync(dataTable);
        }
        catch
        {
            Console.WriteLine(ex.Message);
        }
    }
}