Return datareader from method

asp.net, c#

Solution

Do you really need the reader, or do you just need some way to iterate over the rows inside it? I suggest an iterator block. You can iterate over your rows inside the source method, and `yield` each row in turn to the caller.

There is a twist with this technique: because you're yielding the same object with each iteration, there are cases where this can cause a problem, and so you're best off also asking for a delegate to copy the contents of the row somewhere. I also like to abstract this to a generic method that can be used for any query, and use the same delegate technique to handle parameter data, like so:

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( ... );
     }
 }

Problem

I have the following method ``` 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; } ``` which im calling like this ``` SqlDataReader reader = MenuDataReader(url); if (reader.HasRows) { while (reader.Read()) { }} ``` however im getting the error message Invalid attempt to call HasRows when reader is closed. can anyone help me out thanks

Original source

Related problems