SqlDataSource_OnSelected: 获取数据(DataTable)而不重新执行查询
SqlDataSource_OnSelected: Get data (DataTable) without re-executing the query
我有一个 SqlDataSource 绑定到一个带有 SQL 的 GridView,检索数据大约需要 10 秒。
还有一个名为 "PageSizeControl" 的 UserControl,它挂钩 GridView 的 SqlDataSource 的选定事件。在这种情况下,我需要DataTable来准备PageSizeControl的一些设置。
目前,我正在使用以下代码执行此操作:
protected void ds_Selected(object sender, SqlDataSourceStatusEventArgs e)
{
SqlDataSourceView dsv = (sender as SqlDataSourceView);
dsv.Selected -= ds_Selected;
DataTable dt = (dsv.Select(DataSourceSelectArguments.Empty) as DataView).Table;
int iRowCount = dt.Rows.Count;
// some gui-adaption like visibility, text, ...
}
在旧版本中我们使用 e.AffectedRows。但是当过滤器应用于 DataSource 时,存储在 e.AffectedRows 中的值不正确。我们有一些用例,我们不仅需要行数,还需要整个 DataTable。
问题是,.Select() 重新执行 Db-Query,这又需要 10 秒才能完成。
我还尝试在 SqlDataSource 上启用缓存:
EnableCaching="true" CacheDuration="Infinite"
但这没有帮助,原因有二:
1. 访问缓存数据时不会触发 OnSelected 事件
2. 如果 OnSelected 事件被触发(因为数据尚未缓存),.Select() 仍在未缓存的情况下执行并需要 10 秒。
有没有人知道我如何获取数据而无需耗时地重新执行查询?最好是在 OnSelected 中,但我愿意接受其他建议。
我找到了符合我要求的解决方法 运行。我使用事件 GridView.OnRowDataBound 并获取第一个 GridRow 的 DataItem,其中包含 DataTable。
private DataTable oData = null;
protected void gv_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (oData == null && e.Row.DataItem != null)
{
oData = (e.Row.DataItem as DataRowView).Row.Table;
}
}
此解决方案有效,但它看起来很脏,并且需要 GridView(在我的情况下没问题)。如果有更干净的解决方案,我将不胜感激。
更新
在对 IlSpy 进行更长时间的研究后,我得出的结论是无法在 OnSelected 事件中获取数据。即使启用缓存也不会,因为缓存是在 OnSelected 之后写入的。
所以最简单的方法是打开缓存并在需要数据的地方调用 SqlDataSource.Select(...) 函数。
另一种方法是自己使用SqlDataSource.Select(...) 获取数据,然后将table 绑定到控件。但这有一些缺点。例如:当绑定到 dataset/datatable.
时,GridView 上的排序和分页无法开箱即用
还有一种方法是从选择它的控件中提取数据。请参阅上面的 GridView 示例。
我有一个 SqlDataSource 绑定到一个带有 SQL 的 GridView,检索数据大约需要 10 秒。
还有一个名为 "PageSizeControl" 的 UserControl,它挂钩 GridView 的 SqlDataSource 的选定事件。在这种情况下,我需要DataTable来准备PageSizeControl的一些设置。
目前,我正在使用以下代码执行此操作:
protected void ds_Selected(object sender, SqlDataSourceStatusEventArgs e)
{
SqlDataSourceView dsv = (sender as SqlDataSourceView);
dsv.Selected -= ds_Selected;
DataTable dt = (dsv.Select(DataSourceSelectArguments.Empty) as DataView).Table;
int iRowCount = dt.Rows.Count;
// some gui-adaption like visibility, text, ...
}
在旧版本中我们使用 e.AffectedRows。但是当过滤器应用于 DataSource 时,存储在 e.AffectedRows 中的值不正确。我们有一些用例,我们不仅需要行数,还需要整个 DataTable。
问题是,.Select() 重新执行 Db-Query,这又需要 10 秒才能完成。
我还尝试在 SqlDataSource 上启用缓存:
EnableCaching="true" CacheDuration="Infinite"
但这没有帮助,原因有二: 1. 访问缓存数据时不会触发 OnSelected 事件 2. 如果 OnSelected 事件被触发(因为数据尚未缓存),.Select() 仍在未缓存的情况下执行并需要 10 秒。
有没有人知道我如何获取数据而无需耗时地重新执行查询?最好是在 OnSelected 中,但我愿意接受其他建议。
我找到了符合我要求的解决方法 运行。我使用事件 GridView.OnRowDataBound 并获取第一个 GridRow 的 DataItem,其中包含 DataTable。
private DataTable oData = null;
protected void gv_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (oData == null && e.Row.DataItem != null)
{
oData = (e.Row.DataItem as DataRowView).Row.Table;
}
}
此解决方案有效,但它看起来很脏,并且需要 GridView(在我的情况下没问题)。如果有更干净的解决方案,我将不胜感激。
更新 在对 IlSpy 进行更长时间的研究后,我得出的结论是无法在 OnSelected 事件中获取数据。即使启用缓存也不会,因为缓存是在 OnSelected 之后写入的。
所以最简单的方法是打开缓存并在需要数据的地方调用 SqlDataSource.Select(...) 函数。
另一种方法是自己使用SqlDataSource.Select(...) 获取数据,然后将table 绑定到控件。但这有一些缺点。例如:当绑定到 dataset/datatable.
时,GridView 上的排序和分页无法开箱即用还有一种方法是从选择它的控件中提取数据。请参阅上面的 GridView 示例。