我有一个函数,它使用给定的commandtext执行一个datareader,并为读者返回的每个数据记录调用一个给定的动作。
由于datareader是一个只向前的阅读器,我无法从datareader获取行数。要调用进度条,我必须知道我的datareader将返回的记录数。
我目前的尝试是这样的:
protected void RunConversion(string commandText, Action<IDataRecord> actionConversion)
{
try
{
var curIndex = 0;
var maxIndex = this.Source.ExecuteScalar<int?>($"SELECT COUNT(*) FROM ({commandText}) AS QUERY"); //Here i try to get the count of rows from the result
OnProgress?.Invoke(0);
foreach (var dataRecord in this.Source.ExecuteReader(commandText))
{
try
{
actionConversion?.Invoke(dataRecord);
}
catch (Exception e)
{
OnReport?.Invoke($"Error: {e}{Environment.NewLine}");
}
finally
{
OnProgress?.Invoke((int)((double)++curIndex / maxIndex * 100f));
}
}
}
catch (Exception e)
{
OnReport?.Invoke($"Fatal Error: {e}{Environment.NewLine}");
OnProgress?.Invoke(100);
}
}
问题是,有时commandText-Parameter包含一个查询,其中包含order by ...而不使用top by order by子查询中不允许。
另一种尝试是提供thrid参数,该参数是仅计算当前commandText-Parameter结果的查询。这不是一个好的解决方案,因为我必须编写两个查询,它们可能非常复杂。
想要一个简单的解决方案吗?
答案 0 :(得分:0)
您提到您不能使用计数,因为您使用的是DataReader
。您是否正在显示查询的进度条?如果是这样,我建议不要使用进度条,只需显示“等待”图标,而不是执行两次查询,并延长用户等待显示等待时间的时间。
考虑到这一点,您有两种选择。第一个是取消进度条和SELECT COUNT(*) FROM (...);
,只是按原样传递查询。然后,当您执行它并获得结果集时,如果仍需要显示进度条以进行记录处理,则可以对记录进行计数。当然,如果您不打算使用实际数据,这会给您的操作增加数据传输开销的缺点,所以如果值得多花一点额外的债务,这取决于您。
您的第二个选择是通过执行以下操作简单地删除任何查询的ORDER BY
部分:
public string RemoveOrderBy(string query)
{
return query.SubString(0, query.IndexOf("ORDER BY"));
}
这将删除任何ORDER BY
语句,但如果您在子查询中有任何其他可能无法解决的问题,则必须以与上述相同的方式对其进行说明。