Scenario: We have a DataGridView which is attached to DataAdapter (datatable), we load the data in datatable using (adapter.fill(query, datatable)) in a separate thread (using delegate and beginInvoke) and once the data is loaded we attached that datatable to datagridview (in the main thread)
Is there a way we can check if fill() is still executing and cancel it.

Real scenario: User click on the user name and corresponding data is loaded in the datagrid. Sometime, user is impatient and click on the another user (here I want to cancel the previous fill and start a new fill)

UPDATE: We keep two DataApdaters (and two DataTables) and we attach one datatable to datagridview and start loading data to another datatable asynchronously. When data is loaded we simply bind the datagridview to DataTable which we just filled (and start loading the previous datable asynchronously) This way UI will always get the current data (without user waiting on UI to refresh or hang)


You can provide a SqlCommand to adapter constructor and invoke a Cancel method on it. There is a raw template :

class Model
{
private SqlCommand loadUserCommand;
private DataTable userData; public void LoadUser(string userId)
{
loadUserCommand = GetUserLoadCommandForUserID(userId);
userData = new DataTable("userData");
using (var adapter = new SqlDataAdapter(loadUserCommand))
{
adapter.Fill(userData);
}
} public void AbortLoadUser()
{
if (loadUserCommand!= null)
loadUserCommand.Cancel();
} private SqlCommand GetUserLoadCommandForUserID(string userId)
{
var connection = new SqlConnection("...");
var command = connection.CreateCommand();
...
}
}

注意,在执行SqlCommand.Cancel()方法时,如果SqlDataAdapter.Fill方法还没有执行完毕,那么SqlDataAdapter.Fill方法会抛出SqlException异常,所以为了安全起见,我们应该在代码中包含异常捕获和处理逻辑,如下所示:

class Model
{
private SqlCommand loadUserCommand;
private DataTable userData; public void LoadUser(string userId)
{
loadUserCommand = GetUserLoadCommandForUserID(userId);
userData = new DataTable("userData"); try
{
using (var adapter = new SqlDataAdapter(loadUserCommand))
{
adapter.Fill(userData);
}
}
catch (SqlException ex)
{
//异常处理逻辑
}
} public void AbortLoadUser()
{
if (loadUserCommand != null)
loadUserCommand.Cancel();
} private SqlCommand GetUserLoadCommandForUserID(string userId)
{
var connection = new SqlConnection("...");
var command = connection.CreateCommand();
...
}
}

同理,SqlCommand.Cancel()方法也可以用来取消SqlDataReader的执行,如下所示:

using Microsoft.Data.SqlClient;
using System;
using System.Data;
using System.Threading.Tasks; namespace NetCoreADOTesting
{
class Program
{
static SqlCommand currentCommand = null; public static async Task RunSql()
{
int row = ; try
{
string strConn = "Data Source=192.168.1.1;Initial Catalog=TestDB; User Id=sa;Password=TUI123456";
string sql = @"SELECT [ID]
,[Name]
,[Age]
FROM [dbo].[People];
waitfor delay '1:00';
"; using (SqlConnection sqlConnection = new SqlConnection(strConn))
{
sqlConnection.Open(); using (SqlCommand sqlCommand = new SqlCommand(sql, sqlConnection))
{
currentCommand = sqlCommand;
sqlCommand.CommandTimeout = ; using (SqlDataReader sqlDataReader = currentCommand.ExecuteReader())
{
if (sqlDataReader.HasRows)
{
while (sqlDataReader.Read())
{
//有数据从SqlDataReader中读到
row++;
}
}
}
}
} Console.WriteLine("SqlDataReader row count is {0}", row);
}
catch (SqlException ex)
{
//异常处理逻辑
Console.WriteLine(ex.ToString());
} await Task.CompletedTask;
} static void Main(string[] args)
{
Task t = Task.Run(async () =>
{
await RunSql();
}); Console.WriteLine("Press any key to cancel...");
Console.ReadKey(); if (currentCommand != null)
{
currentCommand.Cancel();
} Console.WriteLine("Press any key to end...");
Console.ReadKey();
}
}
}

这里有一点需要注意,如果SqlCommand.Cancel()方法在生成SqlDataReader之前就被调用了(上面黄色代码行之前),是不会起作用的, SqlDataReader还是会被执行,除非再次调用SqlCommand.Cancel()方法,SqlDataReader的执行才会被取消,并抛出SqlException异常。也就是说SqlCommand.Cancel()方法一定要在SqlDataReader执行之后调用,才能取消SqlDataReader的执行。同样,SqlCommand.Cancel()方法如果在SqlDataAdapter.Fill方法之前执行,也是不起作用的,这是SqlCommand.Cancel()方法的一个缺陷,因为调用SqlCommand.Cancel()方法时,我们并不知道SqlDataReader和SqlDataAdapter是否正在执行。

因此最好的办法还是用SqlCommand.ExecuteReaderAsync(CancellationToken cancellationToken)方法和SqlDataReader.ReadAsync(CancellationToken cancellationToken)方法,结合CancellationToken参数来取消执行。注意,如果CancellationToken参数被取消,ExecuteReaderAsyncReadAsync方法会抛出TaskCanceledException异常,同样我们在代码中要包含异常捕获和处理逻辑,如下所示:

using Microsoft.Data.SqlClient;
using System;
using System.Data;
using System.Threading;
using System.Threading.Tasks; namespace NetCoreADOTesting
{
class Program
{
static CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); public static async Task RunSql()
{
int row = ; try
{
string strConn = "Data Source=192.168.1.1;Initial Catalog=TestDB; User Id=sa;Password=TUI123456";
string sql = @"SELECT [ID]
,[Name]
,[Age]
FROM [dbo].[People];
waitfor delay '1:00';
"; using (SqlConnection sqlConnection = new SqlConnection(strConn))
{
sqlConnection.Open(); using (SqlCommand sqlCommand = new SqlCommand(sql, sqlConnection))
{
sqlCommand.CommandTimeout = ; using (SqlDataReader sqlDataReader = await sqlCommand.ExecuteReaderAsync(cancellationTokenSource.Token))
{
if (sqlDataReader.HasRows)
{
while (await sqlDataReader.ReadAsync(cancellationTokenSource.Token))
{
//有数据从SqlDataReader中读到
row++;
}
}
}
}
} Console.WriteLine("SqlDataReader row count is {0}", row);
}
catch (TaskCanceledException ex)
{
//异常处理逻辑
Console.WriteLine(ex.ToString());
}
} static void Main(string[] args)
{
Task t = Task.Run(async () =>
{
await RunSql();
}); Console.WriteLine("Press any key to cancel...");
Console.ReadKey(); if (cancellationTokenSource != null)
{
cancellationTokenSource.Cancel();
} Console.WriteLine("Press any key to end...");
Console.ReadKey();
}
}
}

这样,只要我们执行了CancellationTokenSource.Cancel()方法,那么SqlCommand.ExecuteReaderAsync(CancellationToken cancellationToken)方法和SqlDataReader.ReadAsync(CancellationToken cancellationToken)方法都会被取消执行,并抛出TaskCanceledException异常。

原文链接

如何取消 SqlDataAdapter.Fill() 的执行(转载)的更多相关文章

  1. C#中SqlDataAdapter的使用小结---转载

    C#中SqlDataAdapter的使用小结 转载 叁木-Neil 最后发布于2018-06-07 21:29:39 阅读数 8275 收藏 展开 SqlDataAdapter对象 一.特点介绍1.表 ...

  2. C#里sqlDataAdapter.fill(DataSet,String)的用法

    第二个参数 String是指定DataSet 里表的名字,例如 sqlDataAdapter.fill(DataSet,"学生表") 指定后,以后就可以这样调用这张表 DataSe ...

  3. iis7如何取消目录的可执行权限

    我们需要把IIs中某一个目录的可执行权限去掉.这在IIs6中是非常方便的,可是因为iis7的机制小编也找了不少资料才找到. 第一步:先选择需要取消权限的目录,然后在右边可以看到 “处理程序映射” 双击 ...

  4. Mac OSX取消Apache(httpd)开机启动(转载)

    启动服务时提示Apache启动失败,80端口被占用.查看进程发现存在几个httpd. OS X自带Apache,可是默认是没有启动的.我也没有开启Web共享,怎么就开机启动了呢? 不知道是不是因为安装 ...

  5. 有三个线程T1 T2 T3,如何保证他们按顺序执行-转载

    T3先执行,在T3的run中,调用t2.join,让t2执行完成后再执行t3 在T2的run中,调用t1.join,让t1执行完成后再让T2执行 public class Test { // 1.现在 ...

  6. 神奇的问题记录【SqlDataAdapter Fill DataSet】

    今天发现程序中有一张报表查询速度很慢[全条件要二分钟左右],查找相关原因,准备进行优化处理.注:报表调用存储过程,存储过程返回两个table就有以下神奇的故事: 直接将SQL语句在SSMS中执行发现全 ...

  7. flask请求异步执行(转载)

    Flask默认是不支持非阻塞IO的,表现为: 当 请求1未完成之前,请求2是需要等待处理状态,效率非常低. 在flask中非阻塞实现可以由2种: 启用flask多线程机制 # Flask from f ...

  8. window IIS6/IIS7取消脚本执行权限,禁止运行脚本木马

    网站安全中,对目录的执行权限是非常敏感的,一般来说,可以写入的目录是不能够拥有脚本的执行权限的,可写入的目录如: data.uploads,data目录主要是基本配置文件和缓存数据,uploads则是 ...

  9. 调用SqlCommand或SqlDataAdapter的Dispose方法,是否会关闭绑定的SqlConnection?(转载)

    1. Does SqlCommand.Dispose close the connection? 问 Can I use this approach efficiently? using(SqlCom ...

随机推荐

  1. ASP.NET Core框架深度学习(四)宿主对象

    11.WebHost  第六个对象 到目前为止我们已经知道了由一个服务器和多个中间件构成的管道是如何完整针对请求的监听.接收.处理和最终响应的,接下来来讨论这样的管道是如何被构建出来的.管道是在作为应 ...

  2. Java生鲜电商平台-订单架构实战

    Java生鲜电商平台-订单架构实战 生鲜电商中订单中心是一个电商后台系统的枢纽,在这订单这一环节上需要读取多个模块的数据和信息进行加工处理,并流向下一环节:因此订单模块对一电商系统来说,重要性不言而喻 ...

  3. Vuex基本使用的总结--转载

    在 Vue 的单页面应用中使用,需要使用Vue.use(Vuex)调用插件.使用非常简单,只需要将其注入到Vue根实例中. import Vuex from 'vuex' Vue.use(Vuex) ...

  4. 重新安装和更新所有的 nuget包

    重新安装指定项目中所有的 nuget 包 Update-Package -ProjectName MyProject –reinstall 更新指定项目中所有的 nuget 包 Update-Pack ...

  5. haproxy动静分离的验证

    线上出现过项目的静态文件被拦截,不能直接访问.所以想到了haproxy指向对应的url来访问静态文件,想到这里在网络搜索了下,确实有此功能.立即上测试环境验证下: 在listen中增加两行: ​ #定 ...

  6. Mysql中 instr与concat

    #INSTR(字符串, 子串),#返回值:第一个子串的索引-1#类似indexOf()#例如:SELECT INSTR('人民万岁,世界万岁','万')SELECT INSTR('人民万岁,世界万岁' ...

  7. Linux常见系统命令和远程管理命令

    系统命令 时间与日期: date(查看系统时间) cal (查看本月日历)  cal -y (查看一年12个月的日历) 磁盘信息: df -h (查看磁盘剩余空间) #重点放于过载点的/ 目录下 du ...

  8. UML类图基础说明

    UML类图主要由类和关系组成. 类: 什么具有相同特征的对象的抽象, 具体我也记不住, 反正有官方定义 关系: 指各个类之间的关系 类图 类就使用一个方框来表示, 把方框分成几层, 来表示不同的信息, ...

  9. c# WF 第5节 窗体的控件

    本节内容: 1:控件在哪里 2:控件怎么添加 3:窗口的显示与隐藏 4:实例单击窗体,出现另一个窗体 1:控件在哪里 视图 --> 工具箱 2:控件怎么添加 第一种:从工具箱直接拉 第二种:在代 ...

  10. 电商网站名词item-->SKU与SPU

    一.总述: item sku spuitem 代表一种商品,是和店铺关联的.sku 商品的库存量单位 , 代表商品的规格和属性spu 产品单位最小分割的商品 ,与商家无关 它的属性会影响价格. 简单的 ...