C# - DataReader 跳过第一个结果

C# - DataReader skipping first result

想看看我是否能在这方面得到一些帮助。我有一个 BackgroundWorker 将执行 SQL 查询,然后在进度更改事件期间更新 DataGridView。但是,它会跳过第一行并将重复的最后一行添加到 DGV。 headers 列已关闭,因为我在 UID 中添加了故障排除。所以请忽略标题与数据不符。

我检查了 Read()IF 中的常见罪魁祸首,但事实并非如此。

有趣的是,如果我在 reader = Sqlcmd.ExecuteReader(); 上打断并单步执行它,它会随机工作。

如有任何帮助,我们将不胜感激!我完全不知所措。


此外,如果我可以将 DGV 添加从更改的进度移动到完成事件,那也将是一个巨大的好处。

/// DO WORK
private void issueBWworker_DoWork_1(object sender, DoWorkEventArgs e)
{
    // DGV 1
    RetriveTableData Obj = (RetriveTableData)e.Argument;
    string SqlcmdString = "SELECT * FROM xBETA_OAP_ISSUE";
    SqlDataReader reader;
    int i = 1;
    try
    {
        using (SqlConnection conn = new SqlConnection(ConnString))
        {
            Sqlcmd = new SqlCommand(SqlcmdString, conn);
            conn.Open();
            reader = Sqlcmd.ExecuteReader();
            if (reader.HasRows)
            {
                while (reader.Read())
                {
                    Obj.uid = reader["id"].ToString();
                    Obj.iss_type = reader["issue_type"].ToString();
                    Obj.inc_num = reader["ticket_num"].ToString();
                    Obj.create_date = reader["create_date"].ToString();
                    Obj.created_by = reader["created_by"].ToString();
                    Obj.active = reader["active"].ToString();
                    Obj.change_date = reader["change_date"].ToString();
                    Obj.changed_by = reader["changed_by"].ToString();

                    Thread.Sleep(100);

                    //MessageBox.Show(Obj.uid);

                    // To Report progress.x
                    issueBWworker.ReportProgress(i, Obj);
                    if (issueBWworker.CancellationPending)
                    {
                        // Set the e.Cancel flag so that the WorkerCompleted event
                        // knows that the process was cancelled.
                        e.Cancel = true;
                        issueBWworker.ReportProgress(0);
                        return;
                    }
                    i++;
                }
                conn.Close();
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}
/// Progress Changes

private void issueBWworker_ProgressChanged_1(object sender, ProgressChangedEventArgs e)
{
    if (!issueBWworker.CancellationPending)
    {
        // DGV 1
        RetriveTableData Obj = (RetriveTableData)e.UserState;
        issue_dgv.Rows.Add(Obj.uid.ToString(), Obj.iss_type.ToString(), Obj.inc_num.ToString(), Obj.create_date.ToString(), Obj.created_by.ToString(), Obj.active.ToString(), Obj.change_date.ToString(), Obj.changed_by.ToString());

        pbar.Value = e.ProgressPercentage;
        //toolStripStatusLabel1.Text = "Processing row.. " + e.ProgressPercentage.ToString() + " of " + TotalRecords;
    }
}
/// Complete
private void issueBWworker_RunWorkerCompleted_1(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled)
    {
        //toolStripStatusLabel1.Text = "Cancelled by User Intentionally...";
        pbar.Value = 0;
        pbar.Visible = false;
    }
    // Check to see if an error occurred in the background process.
    else if (e.Error != null)
    {
        //toolStripStatusLabel1.Text = e.Error.Message;
        pbar.Visible = false;
    }
    else
    {
        // BackGround Task Completed with out Error
        pbar.Visible = false;
        //toolStripStatusLabel1.Text = " All Records Loaded...";
    }
}

根据 documentation,在备注部分中提到对 ReportProgress 的调用是异步的,returns 是立即调用。但是,为了使其与您的代码一起按预期工作,您需要它同步 运行。

这是因为您正在使用同一个对象 Obj,将 reader 每次迭代的数据传递给 ReportProgress - 并且可能使用 Thread.Sleep(100) 作为一种同步方式 - 这并不是真正有效的设计,可能会导致您看到的行为。

例如,假设数据有四行,这将是结果:

+--------+-----------------------------------+--------------------------------------------+
|        | DoWork                            | ReportProgress                             |
+--------+-----------------------------------+--------------------------------------------+
| 1      | Populate values of Obj with row 1 |                                            |
+--------+-----------------------------------+--------------------------------------------+
| 2      | Wait 100 ms                       |                                            |
+--------+-----------------------------------+--------------------------------------------+
| 3      | Dispatch ReportProgress           |                                            |
+--------+-----------------------------------+--------------------------------------------+
| 4      | Populate values of Obj with row 2 |                                            |
+--------+-----------------------------------+--------------------------------------------+
| 5      | Wait 100 ms                       | Add a row with values of Obj, now at Row 2 |
+--------+-----------------------------------+--------------------------------------------+
| 6      | Dispatch ReportProgress           |                                            |
+--------+-----------------------------------+--------------------------------------------+
| 7      | Populate values of Obj with row 3 |                                            |
+--------+-----------------------------------+--------------------------------------------+
| 8      | Wait 100 ms                       | Add a row with values of Obj, now at Row 3 |
+--------+-----------------------------------+--------------------------------------------+
| 9      | Dispatch ReportProgress           |                                            |
+--------+-----------------------------------+--------------------------------------------+
| 10     | Populate values of Obj with row 4 |                                            |
+--------+-----------------------------------+--------------------------------------------+
| 11     | Wait 100 ms                       | Add a row with values of Obj, now at Row 4 |
+--------+-----------------------------------+--------------------------------------------+
| 12     | Dispatch ReportProgress           |                                            |
+--------+-----------------------------------+--------------------------------------------+
| 13     | End of iteration, no more rows    | Add a row with values of Obj, now at Row 4 |
+--------+-----------------------------------+--------------------------------------------+

如何解决?

最简单的方法是在每次迭代中使用 Obj 的新实例。这样,每次调用 ReportProgress 都有自己的实例,不会更改。

换句话说,假设 RetrieveTableData 是一个简单的对象,其构造函数不需要任何参数。我故意保持你原来的风格而不是重写一切..我们可以在这里讨论很多问题,代码风格,变量名称,但它与问题没有直接关系......

while (reader.Read())
{
    var Obj = new RetriveTableData(); // create a new instance
    Obj.uid = reader["id"].ToString();
    Obj.iss_type = reader["issue_type"].ToString();
    ...

我们将不再需要方法顶部的这一行;重点是更改 Obj 的范围,因此我们不会在每次迭代中重复使用它。

RetriveTableData Obj = (RetriveTableData)e.Argument;

Thread.Sleep(100) 也将不再需要。

为了解决在完成事件而不是进度事件中创建数据行的额外目标,您可以将这些单独的 RetrieveTableData 对象收集到 List<RetrieveTableData> 中,并将其传递给您的 RunWorkerCompleted 事件处理程序通过 e.ResultDoWorkEventArgs.