2016-06-06 2 views
1

У меня есть эта проблема: Неправильная попытка вызвать HasRows, когда читатель закрыт. Я пробовал много; удаление соединения закрывает линию, закрывая соединение в конце. но с той же проблемой. Я не могу понять, что не так с моим кодом.Неправильная попытка вызова HasRows, когда читатель закрыт

try 
{ 
    con = new SqlConnection(ConfigurationManager.ConnectionStrings["TextItConnectionString"].ConnectionString); 
    using (con) 
    { 
     con.Open(); 
     Library.writeErrorLog("connection build and open"); 
     SqlCommand cmd = con.CreateCommand(); 
     using (cmd) 
     { 
      cmd.CommandText = "Select [name] From [dbo].[Users]"; 
      SqlDataReader reader = cmd.ExecuteReader(); 
      using (reader) 
      { 
       user.dt.Load(reader); 
       if (reader.HasRows) 
       { 
        while (reader.Read()) 
        { 
         Library.writeErrorLog(reader.GetString(0)); 
        } 
       } 
       else 
        Library.writeErrorLog("no rows"); 
       reader.Close(); 
       con.Close(); 
      } 
     } 
    } 
    //SqlDataAdapter adap = new SqlDataAdapter("Select [name] From [dbo].[Users]", con); 
    //adap.Fill(user.dt); 
} 
catch (Exception ex) 
{ 
    Library.writeErrorLog(ex); 
} 

Спасибо за помощь!

+0

Не могли бы вы показать метод user.dt.Load()? –

+3

Я предполагаю, что 'user.dt' возвращает' DataTable'. Вы знаете, что 'DataTable.Load (reader)' будет содержать всю запись из набора результатов и продвигает читателя к следующему набору? Я спрашиваю, потому что вы используете 'HasRows' ** после ** вы уже использовали' DataTable.Load'. Замечание: вам не нужно использовать 'reader.Close' или' con.Close', если вы используете 'use'-statement. –

+1

Если вы посмотрите на исходный источник [DataTable.Load] (http://referencesource.microsoft.com/#System.Data/System/Data/DataTable.cs,a907a83034e99786), вы можете ясно видеть, что DataReader закрыт до выхода из метод. – Steve

ответ

3

Я предполагаю, что user.dt возвращает DataTable. Вы знаете, что DataTable.Load(reader) будет потреблять все записи набора результатов и продвигает читателя к следующему набору? Я спрашиваю, потому что вы используете HasRowsпосле вы уже использовали DataTable.Load.

Как Steve has commented

Looking at the reference source of DataTable.Load you could clearly see that the DataReader is closed before exiting from the method.

Так что, если нет другого ResultSet (f.e. SELECT * FROM T1;SELECT* from T2) читатель будет закрыт в конце Load что вызовет исключение, если вы пытаетесь использовать SqlDataReader.HasRows.

Я бы назвал это недостатком документации так как он упоминается нигде на MSDN.

Так или использовать

  1. reader.Read и reader.GetString в петлю и добавить его в DataTable вручную,
  2. использование DataTable.Load и петля таблицы после или
  3. использование SqlDataAdapter.Fill(table):

1) while петля и ручное заполнение таблицы

using (SqlDataReader reader = cmd.ExecuteReader()) 
{ 
    if(reader.HasRows) 
    { 
     while (reader.Read()) 
     { 
      string name = reader.GetString(0); 
      user.dt.Rows.Add(name); 
      Library.writeErrorLog(name); 
     } 
    } 
    else 
     Library.writeErrorLog("no rows"); 
} 

2) требует двух циклов, один в DataTable.Load и foreach

using (SqlDataReader reader = cmd.ExecuteReader()) 
{ 
    if(reader.HasRows) 
    { 
     user.dt.Load(reader); // all records added 
     foreach(DataRow row in user.dt.Rows) 
     { 
      string name = row.Field<string>(0); 
      Library.writeErrorLog(name); 
     } 
    } 
    else 
     Library.writeErrorLog("no rows"); 
} 

3) другой вариант заключается в использовании SqlDataAdapter и это Fill(dataTable) метод:

using (var da = new SqlDataAdapter(cmd)) 
{ 
    da.Fill(user.dt); 
    if (user.dt.Rows.Count > 0) 
    { 
     foreach (DataRow row in user.dt.Rows) 
     { 
      string name = row.Field<string>(0); 
      Library.writeErrorLog(name); 
     } 
    } 
    else 
     Library.writeErrorLog("no rows"); 
} 

Side -номер: вам не нужно использовать reader.Close или con.Close, если вы используете using -statement.

+0

Спасибо @Tim это работает.Теперь я знаю, где я был неправ. Да, это глупая ошибка (Отсутствие документации). Спасибо за помощь мне. –

+1

@MuhammadTauseen: добро пожаловать. Обратите внимание, что я добавил третий подход, используя 'SqlDataAdapter.Fill'. Тогда вам совсем не нужен читатель. Обратите внимание, что вам даже не нужно открывать/закрывать соединение, если вы используете 'SqlDataAdapter.Fill', так как это делается автоматически (но это не мешает сделать это). –

+0

ой большой. Еще раз спасибо. У меня другая проблема. Вышеупомянутый код - это моя служба Windows. Я хочу загрузить данные из моей службы Windows на веб-страницу. после загрузки данных в DataTable dt, я вызываю функцию из файла Default.aspx.cs для загрузки в gridview В файле Default.aspx.cs 'GridView1.DataSource = dt; GridView1.DataBind(); ' Ошибка: ссылка на объект не установлена ​​в экземпляр объекта. –

Смежные вопросы