如何知道何时停止填充OracleDataAdapter?

4
我正在使用OPD.NET dll访问oracle数据库的项目。用户可以在文本框中输入任何SQL语句,然后执行该查询。我一直试图使用OracleDataAdapter将结果集填充到数据表中,但是我想能够分阶段返回结果集(对于大型选择查询)。
我的问题示例是...
如果一个选择查询返回了13行数据,下面的代码片段将执行4次oda.Fill(开始行是15,不存在),我认为这是因为它调用了已关闭或类似的读取器。
然后它将抛出System.InvalidOperationException异常,其中包含消息-由于对象的当前状态,操作无效。
如何找出命令最终会包含多少行(以便避免异常)?
OracleDataAdapter oda = new OracleDataAdapter(oracleCommand);
oda.Requery = false;

var dts = new DataTable[] { dt };
DataTable dt = new DataTable();

oda.Fill(0, 5, dts);
var a = dts[0].Rows.Count;
oda.Fill(a, 5, dts);
var b = dts[0].Rows.Count;
oda.Fill(b, 5, dts);
var c = dts[0].Rows.Count;
oda.Fill(c, 5, dts);
var d = dts[0].Rows.Count;

注意:为了简洁起见,我省略了连接和Oracle命令对象。
编辑1: 我刚想到可以将用户输入的SQL语句包装在另一个查询中并执行它... SELECT COUNT(*) FROM (...这里是初始查询...) 但这不是一个很干净的解决方案,肯定有我没看到的方法吧?
提前感谢。
3个回答

1

关于Oracle的分页,请参见:http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html

如果不运行单独的count(*)查询,就无法知道记录集计数。这是有意设计的。DataReader和DataAdapter只能向前读取,只读。

如果效率是一个问题(即大型记录集),应该让数据库进行分页,而不是要求OracleDataAdapter运行完整的查询。想象一下,如果Google为每个用户搜索填充包含所有100万多个结果的DataTable!!以下文章解决了这个问题,尽管示例是在SQL中:

http://www.asp.net/data-access/tutorials/efficiently-paging-through-large-amounts-of-data-cs

我已经修改了下面的示例,以允许在任何SQL查询上进行分页。调用过程负责跟踪用户的当前页面和页面大小。如果结果集小于请求的页面大小,则没有更多页面。

当然,从用户输入运行自定义SQL是巨大的安全风险。但这不是手头的问题。

祝好运!--Brett

DataTable GetReport(string sql, int pageIndex, int pageSize)
{
    DataTable table = new DataTable();

    int rowStart = pageIndex * pageSize + 1;
    int rowEnd = (pageIndex + 1) * pageSize;

    string qry = string.Format(
@"select * 
from (select rownum ""ROWNUM"", a.*
    from ({0}) a
    where rownum <= :rowEnd)
where ""ROWNUM"" >= :rowStart
", sql);
    try
    {
        using (OracleConnection conn = new OracleConnection(_connStr))
        {
            OracleCommand cmd = new OracleCommand(qry, conn);
            cmd.Parameters.Add(":rowEnd", OracleDbType.Int32).Value = rowEnd;
            cmd.Parameters.Add(":rowStart", OracleDbType.Int32).Value = rowStart;
            cmd.CommandType = CommandType.Text;
            conn.Open();
            OracleDataAdapter oda = new OracleDataAdapter(cmd);
            oda.Fill(table);
        }
    }
    catch (Exception)
    {
        throw;
    }
    return table;        
}

嗨,Brett,这只是给我提供了一种不同的方式来填充结果集的子集,其中rowStart替换第一个参数,而rowEnd替换第二个参数(要检索多少条记录)。我仍然需要进行单独的查询以找到最大的rowStart。谢谢,链接很有趣。 - Will
听起来你正在尝试使用DataTable作为容器来实现分页解决方案。我不清楚为什么这个分页解决方案不起作用。假设你想每次分页10条记录,那么rowStart和rowEnd应该是(1,20),(21,30),(31,40)等等。当数据表返回为空或少于10行时,你就完成了。 - Brett
使用OracleDataAdapter的fill方法的好处是,它不会实际重新查询数据库(requery=false),而只是填充额外的数据。使用“当数据表返回为空或少于10行时,你就完成了”的逻辑的问题在于,最后一个返回的数据表实际上可能包含最后一行,在这种情况下,异常仍然会被抛出。 - Will
请查看我的修订答案。祝你好运。 - Brett

0
要控制Fill DataTable Loop,您需要掌握循环。
然后,使用OracleDataReader建立自己的函数来填充DataTable。
要获取列信息,可以使用dataReader.GetSchemaTable。
要填充表格:
  MyTable.BeginLoadData 
  Dim Values(mySchema.rows.count-1)
  Do while myReader.read
    MyReader.GetValues(Values)
    MyTable.Rows.add(Values)

    'Include here your control over load Count 
  Loop
  MyTable.EndLoadData

0
你可以在查询中添加分析计数:
SELECT foo, bar, COUNT(*) OVER () TheCount WHERE ...;

这样整个查询的计数将与TheCount中的每一行一起返回,您可以相应地设置循环终止。


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