首页 > 解决方案 > 在 BackgroundWorker 中停止查询阅读器的好方法是什么?

问题描述

我开始使用BackgroundWorker进行尝试,我想知道如何停止返回对象 列表的查询,这可能需要一些时间才能执行。

我想我无法停止服务器上的查询,但我特别要寻找的是停止读取包含此查询结果的SqlDataReader 。

这是我的 BackgroudnWorker 的代码示例和示例查询:

public partial class Form1 : Form
{
    private BackgroundWorker worker;

    public Form1 (Point location)
    {
        this.Location = location;
        InitializeComponent();
        worker = new BackgroundWorker
        {
            WorkerSupportsCancellation = true,
        };
        worker.DoWork += this.Worker_DoWork;
        worker.RunWorkerCompleted += this.Worker_RunWorkerCompleted;
    }

    #region Form
    private void ButtonBack_Click (object sender, EventArgs e)
    {
        if (worker.IsBusy && !worker.CancellationPending)
        {
            worker.CancelAsync();
        }
        this.Close();
    }

    private void TextBoxSearch_TextChanged (object sender, EventArgs e)
    {
        while (worker.IsBusy)
        {
            if (worker.IsBusy && !worker.CancellationPending)
            {
                worker.CancelAsync();
            }
        }

        worker.RunWorkerAsync();
    }
    #endregion

    #region Worker
    private void Worker_RunWorkerCompleted (object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            if (worker.IsBusy && !worker.CancellationPending)
            {
                worker.CancelAsync();
            }

            Console.WriteLine(e.Error.Message);
        }
    }

    private void Worker_DoWork (object sender, DoWorkEventArgs e)
    {
        if (!worker.CancellationPending)
        {
            // Where I'd like to cut the IEnumerable if worker.CancellationPending to shorten time of process
            foreach (LigneHS ligne in GetLignesHS(worker.CancellationPending))
            {
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }

                // Do work
            }
        }
        else
        {
            e.Cancel = true;
            return;
        }
    }
    #endregion

     // Sample query
    internal static IEnumerable<LigneHS> GetLignesHS (bool cancellationPending)
    {
        string requete = "SELECT * FROM [MY_TABLE] ORDER BY [date] DESC";
        SqlConnection conn = BDD.OpenBDD16();
        SqlCommand command = new SqlCommand(requete, conn);

        List<LigneHS> lignes = new List<LigneHS>();
        LigneHS ligne = new LigneHS();

        try
        {
            if (!cancellationPending)
            {
                SqlDataReader reader = command.ExecuteReader();

                while (reader.Read() && !cancellationPending)
                {
                    ligne = new LigneHS();

                    if (reader["id"] != DBNull.Value)
                    {
                        ligne.Id = Convert.ToInt32(reader["id"]);

                        // filtering null values for every column

                        lignes.add(ligne);

                        // tried to add the yield return here, but can't inside a try-catch
                    }
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("GetLignesHS : " + ex.Message);
        }
        finally
        {
            command.Dispose();
            conn.Close();
        }

        return lignes;
    }
}

就像这里一样,如果要求工作人员停止,则查询的 cancelPending 不会更新。

如果 BackgroundWorker 被要求停止,我首先想到使用yield return 来中断 foreach。但是,我在处理查询时使用了 try-catch,所以我不能。

我知道像使用直线程时那样使用CancellationToken会起作用,但我想知道这是否是实现我想要的最佳方式。

标签: c#winformsbackgroundworker.net-4.7.2

解决方案


推荐阅读