C# 从方法返回datareader

C# 从方法返回datareader,c#,asp.net,C#,Asp.net,我有以下方法 public static SqlDataReader MenuDataReader(string url) { using (SqlConnection con = new SqlConnection(connectionString)) { using (SqlCommand cmd = new SqlCommand("spR_GetChildMenus", con)) {

我有以下方法

    public static SqlDataReader MenuDataReader(string url)
    {
        using (SqlConnection con = new SqlConnection(connectionString))
        {
            using (SqlCommand cmd = new SqlCommand("spR_GetChildMenus", con))
            {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.AddWithValue("@PageUrl", url);
                cmd.Parameters.AddWithValue("@MenuId", ParameterDirection.Output);
                cmd.Parameters.AddWithValue("@ParentId", ParameterDirection.Output);
                cmd.Parameters.AddWithValue("@TitleText", ParameterDirection.Output);
                cmd.Parameters.AddWithValue("@ExternalUrl", ParameterDirection.Output);
                cmd.Parameters.AddWithValue("@FullUrl", ParameterDirection.Output);
                cmd.Parameters.AddWithValue("@ChildCount", ParameterDirection.Output);
                con.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                if (reader.HasRows)
                {
                    //return reader;

                    while (reader.Read())
                    {
                        return reader;
                    }

                }
            }
        }
        return null;
    }
我是这样叫的

        SqlDataReader reader = MenuDataReader(url);
        if (reader.HasRows)
        {
            while (reader.Read())
            { }}
但是我收到了错误信息

当读卡器关闭时调用HasRows的尝试无效

有人能帮我吗


谢谢

我不会返回读卡器-您连接的
Dispose
命令正在关闭连接。相反,我将返回数据的代表性模型。

当您使用
语句返回
内部时,代码调用
SqlConnection上的
Dispose
。这将关闭数据读取器,从而导致错误。

您真的需要读取器,还是只需要某种方法来遍历其中的行?我建议使用迭代器块。您可以在源方法内迭代您的行,然后
依次向调用者产生
每一行

这种技术有一个转折点:因为每次迭代都会产生相同的对象,所以在某些情况下,这可能会导致问题,因此最好也让代理将行的内容复制到某个地方。我还想将其抽象为可用于任何查询的通用方法,并使用相同的委托技术处理参数数据,如下所示:

private IEnumerable<T> GetRows<T>(string sql, Action<SqlParameterCollection> addParameters, Func<IDataRecord, T> copyRow)
{
     using (var cn = new SqlConnection("Connection string here"))
     using (var cmd = new SqlCommand(sql, cn)
     {
         cmd.CommandType = CommandType.StoredProcedure;
         addParameters(cmd.Parameters);
         cn.Open();
         using (var rdr = cmd.ExecuteReader())
         {
             while (rdr.Read())
             {
                 yield return copyRow(rdr);
             }
             rdr.Close();
         }
     }
}

public IEnumerable<MenuItem> GetChildMenus(string url)
{
     return GetRows<MenuItem>("spR_GetChildMenus", p =>
     {
         //these lines are copied from your question, but they're almost certainly wrong
         p.AddWithValue("@PageUrl", url);
         p.AddWithValue("@MenuId", ParameterDirection.Output);
         p.AddWithValue("@ParentId", ParameterDirection.Output);
         p.AddWithValue("@TitleText", ParameterDirection.Output);
         p.AddWithValue("@ExternalUrl", ParameterDirection.Output);
         p.AddWithValue("@FullUrl", ParameterDirection.Output);
         p.AddWithValue("@ChildCount", ParameterDirection.Output);
     }, r =>
     {
         return new MenuItem( ... );
     }
 }
private IEnumerable GetRows(字符串sql、操作addParameters、Func copyRow)
{
使用(var cn=new-SqlConnection(“此处为连接字符串”))
使用(var cmd=new SqlCommand(sql,cn)
{
cmd.CommandType=CommandType.storedProcess;
addParameters(命令参数);
cn.Open();
使用(var rdr=cmd.ExecuteReader())
{
while(rdr.Read())
{
收益返回复写行(rdr);
}
rdr.Close();
}
}
}
公共IEnumerable GetChildMenus(字符串url)
{
返回GetRows(“spR_GetChildMenus”,p=>
{
//这些台词是从你的问题中抄来的,但它们几乎肯定是错的
p、 AddWithValue(“@PageUrl”,url);
p、 AddWithValue(“@MenuId”,ParameterDirection.Output);
p、 AddWithValue(“@ParentId”,ParameterDirection.Output);
p、 AddWithValue(“@TitleText”,ParameterDirection.Output);
p、 AddWithValue(“@ExternalUrl”,ParameterDirection.Output);
p、 AddWithValue(“@FullUrl”,ParameterDirection.Output);
p、 AddWithValue(“@ChildCount”,ParameterDirection.Output);
},r=>
{
返回新的菜单项(…);
}
}
如图所示:


有没有关于如何操作的线索?您可以从函数返回读取器,但前提是您将连接对象作为参数传递给它。您可以使用“CommandBehavior.CloseConnection”选项创建读取器,以便在读取器关闭时自动关闭。必须找到一种很难的方法:当您在
while(reader.Read())中时
构造您的对象,然后返回一个
列表
@Ric,这有点违背了使用datareader的目的。您并不比Fill()好多少-此时正在删除数据集。有一些方法可以保留DataReader每次一条记录的特性。当然可以,但是如果处理了连接,那么您的命令将导致执行某些操作,而不是返回读取器。这就是我从这个答案中得到的,也是我将要做的,返回强类型对象etcAre你确定它不返回Null?为什么要返回阅读器?我已经修改为“abbas”当读卡器关闭时,调用HasRows的尝试无效。所以我想我需要更改it@andrewslaughter读卡器依赖于SqlConnection。当您退出using语句时,SqlConnection将关闭,此后您将无法使用读卡器。我将同意Daniel A White的建议,阅读您的rea在退出该方法之前删除。或者将一个SqlConnection传递到该方法中,这样它就不会像Yuriy Galanter建议的那样关闭。这是我最喜欢的解决方案。这是一个非常好的答案。您可以更进一步,使一切
IDataReader
IDbCommand
IDbConnection
,以及
DbParameter
,re移动Sql依赖项。您将传递
Func dbConnectionFactory
,而不是连接字符串,这是一个创建所需连接的函数。然后,您是否需要确保在返回的读取器周围实现using语句,以确保其正确关闭?连接是否保持打开状态?@TylerNielsen-t中的示例这个链接显示了包装在using语句中的返回的读卡器。请看GetDepartments()函数。在一个特殊的情况下,您真正想要返回读卡器的是在一个单独的数据库中进行批量插入,该数据库有自己的连接。
  public static SqlDataReader ExecuteReader(String connectionString, String commandText,
      CommandType commandType, params SqlParameter[] parameters) {
     SqlConnection conn = new SqlConnection(connectionString);

     using (SqlCommand cmd = new SqlCommand(commandText, conn)) {
        cmd.CommandType = commandType;
        cmd.Parameters.AddRange(parameters);

        conn.Open();
        // When using CommandBehavior.CloseConnection, the connection will be closed when the 
        // IDataReader is closed.
        SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);

        return reader;
     }
  }