取消 DataAdapter.Fill()

6

场景: 我们有一个DataGridView,它附加到DataAdapter(datatable),我们使用(adapter.fill(query,datatable))在单独的线程中(使用委托和beginInvoke)加载datatable中的数据,一旦数据加载完成,我们将该datatable附加到datagridview(在主线程中)

有没有办法检查fill()是否仍在执行并取消它。

真实情况: 用户点击用户名,相应的数据加载到datagrid中。 有时,用户会不耐烦地点击另一个用户(在这里我想取消以前的填充并开始新的填充)

更新: 我们保留两个DataApdaters(和两个DataTables),并将一个datatable附加到datagridview并异步开始加载数据到另一个datatable。当数据加载完成后,我们只需将datagridview绑定到我们刚刚填充的DataTable(并异步开始加载上一个datable)。 这样,UI将始终获得当前数据(而无需等待UI刷新或挂起)


3
请不要在标题中添加类似"C# ADO.net"这样的内容。这就是[SO]上标签的用途。 - John Saunders
1
@James,如果主线程(UI)正在填充数据的工作,那么UI将会无响应,这被认为是非常粗糙的。 - Kirk Woll
1
@James 在 UI 线程上执行长时间的数据库操作是锁定 UI 的好方法。 - Adam Lear
3
@James,不要陷入细节中,请问我是否有办法取消已存在(正在执行的)Adapter.fill() 并启动另一个?请帮我翻译此内容。 - karephul
@karephul:你需要发布一些代码。虽然你已经说明了你的做法,但我认为如果没有看到一些代码,任何人都很难回答你的问题。 - James Johnson
显示剩余5条评论
3个回答

2
您可以将SqlCommand提供给适配器构造函数,并在其上调用Cancel方法。 以下是原始模板:

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();
        ...
    }
}

你的模板中没有调用AbortLoadUser。你认为该如何调用它? - Rob Sedgwick
LoadUser和AbortLoadUser是Model类的公共方法,可以从UI中调用,例如从按钮单击事件处理程序中。 - igorushi

0

没有办法“安全”取消DataAdapter.Fill()

为了解决这个问题,一个方案是实现一个机制,可以使这些不必要的填充被忽略,因此不会反映在用户界面上。我建议在异步操作开始时递增一个计数器,并将该状态传递给您的异步操作。然后,当异步操作完成时,您的异步操作可以检查其计数器值与当前计数器的值是否相等。如果计数器不相等,则不更新用户界面。

如果您发现用户快速在不同的选项之间切换并且许多请求被丢弃,请实现一个定时器机制,仅在用户停留在选择上一段最小时间后才检索数据。


真正的问题是,如果我尝试在另一个查询正在执行时再次使用不同的查询调用adapter.fill(query, datatable),它会抛出“IllegalOperationException”。我认为DataAdapter应该公开一个API来检查状态,基于此客户端应该采取适当的措施。 - karephul
我目前正在做同样的事情,自己维护一个标志(执行),并根据此来处理请求。但如果填充需要很长时间,那么我只是在等待我不需要的填充。 - karephul
@karephul 每次调用应该使用一个新的DataAdapter。您不需要等待被忽略的填充。 - Tim Lloyd
我不确定创建新的DataAdapter是否如此便宜,以至于可以为每个fill()实例化一个新的DataAdapter。 - karephul
1
创建适配器很便宜,运行查询才是昂贵的。 - Tim Lloyd

0
我进行了快速搜索并找到了这个:取消 DataAdapter.Fill。似乎没有办法避免处理异常,正如代码作者所述。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接