【问题标题】:DataReader Working Not ClearDataReader 工作不清楚
【发布时间】:2013-03-28 15:16:17
【问题描述】:
 protected void btnFetch_Click(object sender, EventArgs e)
    {

    SqlConnection con = new SqlConnection(Helper.ConStr);
    SqlCommand cmd = new SqlCommand();
    cmd.Connection = con;
    cmd.CommandText = "select * from emptable";
    con.Open();
    SqlDataReader dr = cmd.ExecuteReader();
    gv1.DataSource = dr;
    gv1.DataBind();

    dr.NextResult();

    **while (dr.Read())**//It is returning the value as false!
    {
        SqlCommand cmd1 = new SqlCommand();
        cmd1.CommandText = "select * from table1";
        Response.Write(dr[0]);
        Response.Write(dr[1]);
    }
    con.Close();
 }

我很困惑为什么,数据读取器选择一个“选择语句”,读取它并将其绑定到 Gridview,但是当涉及到使用下一组“选择语句”时,数据读取器没有不做任何事。 dr.Read() 变为 false

请解释一下为什么会这样?

【问题讨论】:

  • NextResult 返回什么?
  • SqlDataReader.NextResult 返回boolean 值顺便说一句
  • 您应该在您的连接和命令上使用“使用”,这样您就不必自己处置/它们,如果发生异常,它们将被处置。

标签: c# asp.net sql sql-server ado.net


【解决方案1】:

数据读取器仅向前。这意味着您只能读取所有行一次。

因此,当您绑定 GridView 后,它将在数据读取器中移动,直到 Read() 返回 false(以便能够填充所有行)。

因此,当您尝试调用循环时,reader 已经在记录集的末尾。

这在MSDN中有详细解释。

更新:

NextResult() 方法用于选择下一个结果,如果您向@Petoj 显示的Command.CommandText 添加了多个 SELECT 语句。因此,它对您的代码没有任何影响。

【讨论】:

  • 感谢您告诉我为什么循环条件中的“dr.read()”结果为假。
【解决方案2】:

试试这个

 protected void btnFetch_Click(object sender, EventArgs e)
 {

    SqlConnection con = new SqlConnection(Helper.ConStr);
    SqlCommand cmd = new SqlCommand();
    cmd.Connection = con;
    cmd.CommandText = "select * from emptable;select * from table1";
    con.Open();
    SqlDataReader dr = cmd.ExecuteReader();
    gv1.DataSource = dr;
    gv1.DataBind();

    dr.NextResult();

    while (dr.Read())
    {
        Response.Write(dr[0]);
        Response.Write(dr[1]);
    }
    con.Close();
 }

【讨论】:

  • 非常感谢。这段代码非常简单,就像一个魅力。问题解决了!
  • 使用连接、命令和阅读器的一个额外提示。这样你就可以摆脱内存泄漏
【解决方案3】:

您不需要NextResultdr.NextResult(); 将阅读器推进到下一批:

using (var myCon = new SqlConnection(Helper.ConStr))
using (var selectCommand = new SqlCommand("select * from emptable", myCon))
{
    myCon.Open();
    using (var dr = selectCommand.ExecuteReader())
    {
        while (dr.Read()) 
        {
            // ...
        }
    }
}

因此,如果您选择两个表,您可以使用NextResult 获取下一个,例如:

"select * from emptable; select * from otherTable"

通常你不需要使用这个方法,因为ExecuteReader 已经返回了第一批。

请注意,我使用using-statement 来确保所有非托管资源都在其末尾进行处理,即使发生异常也是如此。您应该尽可能使用它。这适用于实现IDisposable 的每个对象(如果在不可能的情况下尝试使用using,则会出现编译器错误)。

SqlConnection.Dispose 也会关闭连接,因此您无需手动执行此操作(这适用于所有连接类型)。

MSDN

通常,当您使用IDisposable 对象时,您应该声明并 在 using 语句中实例化它。 using 语句 调用 以正确的方式处理对象上的方法。在 using 块中,对象是 只读,不能修改或重新分配。使用语句 确保调用 Dispose 即使发生异常,而您 正在调用对象上的方法。

【讨论】:

  • Tim,您能否请给我一篇网络上的参考文章,以在您的代码中使用“使用”。我从来没有使用过它。如果可能,请稍微解释一下。
  • @kustomClass:编辑了我的答案(里面有链接)。
【解决方案4】:

dr.NextResult(); 在查询 Reference 中有多个选择语句时有效。
您的表中只有一个选择语句为

cmd.CommandText = "select * from emptable";

所以如果你必须使用多个选择语句,那么在命令文本中你应该有多个选择语句如下

cmd.CommandText = "select * from emptable;select * from table1";

【讨论】:

    【解决方案5】:

    你必须在sql server中写一个存储过程

    创建过程 selectFromTwoTables 作为 开始 开始交易

    SELECT * FROM emptable

    从表 1 中选择 *

    IF(@@error = 0) -- 如果发生任何错误,事务将回滚。否则提交 提交交易 别的 回滚交易 结束

    在 C# 中 SqlCommand cmd = new SqlCommand("selectFromTwoTables", conn); cmd.CommandType = CommandType.StoredProcedure;

    【讨论】: