【问题标题】:C#: Populate DataTable from SqlDataReader with the ability to interrupt?C#:从具有中断能力的 SqlDataReader 填充 DataTable?
【发布时间】:2016-08-17 13:24:00
【问题描述】:

我想通过 SqlDataReader 填充 DataTable 对象并能够中断操作(例如,在用户想要取消长时间运行的查询的情况下通过 u/i)。

不幸的是,我没有看到DataTable.Load() 的任何重载需要CancellationToken。

有没有一种干净的方法来实现这一点?

(我唯一的想法是使用线程并查看Thread.Interrupt() 是否可以解决问题,如果没有,则使用Thread.Abort(),但这似乎很不友好)。

【问题讨论】:

  • 填充数千行需要几毫秒。而不是这样,您可以将条件放在查询本身中。
  • @DheerajRoy 你能解释一下吗?我的查询需要很长时间才能返回包括元数据在内的任何内容。我如何在查询中输入“条件”?
  • 我认为您应该通过 SqlDataAdapter 查看 DataTable RowChanged。

标签: c# sql multithreading datatable


【解决方案1】:

您可以使用任务和取消令牌。当然,您必须手动填充 DataTable,而不是使用 Load 方法。

private void FillTable(CancellationToken token)
{
    var reader = new SqlDataReader();
    var dt = CreateDataTable();
    while(reader.Read() && !token.IsCancellationRequested)
    {
        var row = dt.NewRow();
        // fill row from reader....
        dt.Rows.Add(row);
    }
}

你会像这样使用这个方法:

CancellationTokenSource tokenSource = new CancellationTokenSource();
Task.Factory.StartNew(() => FillTable(tokenSource.Token), tokenSource.Token);

然后就可以取消操作了:

tokenSource.Cancel();

【讨论】:

  • 充实它,我想我会想要reader.ReadAsync()。当我希望元数据基于查询结果时,如何实现CreateDataTable()?谢谢!
  • 我猜你可以这样做DataTable dt = reader.GetSchemaTable();,其中 reader 是 SqlDataReader。
  • ... 回到阻塞慢查询 :-(?我有一些可能需要几分钟才能返回元数据的 doozies(不要问)。
  • 嗯,你需要你的查询返回一些东西来获取模式,没有办法解决这个问题。也许你应该努力优化你的查询。
  • 你应该尝试@William Xifaras 的建议,我认为它会达到你想要达到的效果..
【解决方案2】:

与 SqlDataAdapter 结合使用,您可以处理 DataTable RowChanged 事件并抛出异常或关闭数据适配器的连接,从而引发 InvalidOperationException。

看看下面的例子 (source):

private BackgroundWorker worker;
private DataTable table;

private void button2_Click(object sender, EventArgs e)
{
  if (worker != null)
  {
    worker.CancelAsync();
  }
}

private void button1_Click(object sender, EventArgs e)
{  
  this.worker = new BackgroundWorker();
  worker.WorkerReportsProgress = true;
  worker.WorkerSupportsCancellation = true;

  worker.DoWork += new DoWorkEventHandler(worker_DoWork);
  worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

  worker.RunWorkerAsync();
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  MessageBox.Show(this.table.Rows.Count.ToString());
}

[System.Diagnostics.DebuggerStepThrough]
void worker_DoWork(object sender, DoWorkEventArgs e)
{
  this.table = new DataTable();

  using (SqlConnection connection= new SqlConnection())
  using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM table", connection))
  {
    table.RowChanged += new DataRowChangeEventHandler(table_RowChanged); 
    da.Fill(table);        
  }
}

[System.Diagnostics.DebuggerStepThrough]
void table_RowChanged(object sender, DataRowChangeEventArgs e)
{
  if (worker.CancellationPending)
  {
    throw new ApplicationException("Canceled"); // throw a spanner in the works
  }
  Thread.Sleep(5); // Just slow things down for testing
}

【讨论】:

    猜你喜欢
    • 2011-08-02
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    • 2016-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多