2016-08-17 62 views
0

我想通过SqlDataReader填写一个DataTable对象,并有能力中断操作(例如,在用户想要取消长时间运行的查询的情况下,通过u/i)。C#:从SqlDataReader填充DataTable并具有中断能力?

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

有没有一种干净的方式来实现这一目标?

(我唯一的想法是使用一个线程,看看Thread.Interrupt()是否有窍门,如果不是,然后Thread.Abort(),但似乎很不友好)。

+0

需要毫秒填补数千行。而不是这样,你可以在条件查询本身。 –

+0

@DheerajRoy你能解释一下吗?我有很长的时间来返回包括元数据在内的任何查询。我如何把“条件查询”? – CoderBrien

+0

我想你应该通过SqlDataAdapter查看DataTable RowChanged。 –

回答

0

与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 
} 
2

你可以使用一个任务和取消标记。当然,您将不得不手动填充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(); 
+0

充实它,我想我会想'reader.ReadAsync()'在我的情况。当我希望元数据基于查询结果时,如何实现'CreateDataTable()'?谢谢! – CoderBrien

+0

我想你可以这样做'DataTable dt = reader.GetSchemaTable();'其中reader是SqlDataReader。 – Kinetic

+0

...回到堵塞缓慢的查询:-(?我有一些doozies可能需要几分钟的时间来返回元数据(不要问)。 – CoderBrien