问题
Hello i have a method which reads some data from the sql and saves them to arrays.
to find out how many rows the sql result has i wrote this:
DataTable dt = new DataTable();
dt.Load(rdr);
count = dt.Rows.Count;
after that, the sqldatareader saves the results to arrays.
here is my complete code:
public BookingUpdate[] getBookingUpdates(string token)
{
String command = "SELECT b.ID,b.VERANSTALTER, rr.VON ,rr.BIS, b.THEMA, b.STORNO, ra.BEZEICHNUNG from BUCHUNG b JOIN RESERVIERUNGRAUM rr on rr.BUCHUNG_ID = b.ID JOIN RAUM ra on ra.ID = rr.RAUM_ID WHERE b.UPDATE_DATE BETWEEN DATEADD (DAY , -20 , getdate()) AND getdate() AND b.BOOKVERNR = 0";
SqlConnection connection = new SqlConnection(GetConnectionString());
BookingUpdate[] bookingupdate = new BookingUpdate[1];
connection.Open();
try
{
SqlCommand cmd = new SqlCommand(command, connection);
SqlDataReader rdr = null;
int count = 0;
int c = 0;
rdr = cmd.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(rdr);
count = dt.Rows.Count;
bookingupdate = new BookingUpdate[count];
while (rdr.Read()) // <--- HERE COMES THE ERROR
{
bookingupdate[c] = new BookingUpdate();
bookingupdate[c].bookingID = Convert.ToInt32(rdr["ID"]);
bookingupdate[c].fullUserName = rdr["VERANSTALTER"].ToString();
bookingupdate[c].newStart = (DateTime)rdr["VON"];
bookingupdate[c].newEnd = (DateTime)rdr["BIS"];
bookingupdate[c].newSubject = rdr["THEMA"].ToString();
bookingupdate[c].newlocation = rdr["BEZEICHNUNG"].ToString();
if (rdr["STORNO"].ToString() != null)
{
bookingupdate[c].deleted = true;
}
else
{
bookingupdate[c].deleted = false;
}
c++;
}
}
catch (Exception ex)
{
log.Error(ex.Message + "\n\rStackTrace:\n\r" + ex.StackTrace);
}
finally
{
connection.Close();
}
return bookingupdate;
}
the exeption is : Invalid attempt to call Read when reader is closed
回答1:
The Load-Method closes the DataReader
, hence a following call to Read()
fails (well, that's excatly what the exception tells you).
Once you read the data into your DataTable
, you could simply query it and use a Select
projection to create your BookingUpdate
instances (no need for the while
-loop/BookingUpdate[]
). So your code can basically trimmed down to
String command = "SELECT b.ID,b.VERANSTALTER, rr.VON ,rr.BIS, b.THEMA, b.STORNO, ra.BEZEICHNUNG from BUCHUNG b JOIN RESERVIERUNGRAUM rr on rr.BUCHUNG_ID = b.ID JOIN RAUM ra on ra.ID = rr.RAUM_ID WHERE b.UPDATE_DATE BETWEEN DATEADD (DAY , -20 , getdate()) AND getdate() AND b.BOOKVERNR = 0";
SqlCommand cmd = new SqlCommand(command, new SqlConnection(GetConnectionString()));
connection.Open();
DataTable dt = new DataTable();
dt.Load(cmd.ExecuteReader());
var bookingupdate = dt.Rows.OfType<DataRow>().Select (row =>
new BookingUpdate
{
bookingID = Convert.ToInt32(row["ID"]),
fullUserName = row["VERANSTALTER"].ToString(),
newStart = (DateTime)row["VON"],
newEnd = (DateTime)row["BIS"],
newSubject = row["THEMA"].ToString(),
newlocation = row["BEZEICHNUNG"].ToString(),
deleted = row["STORNO"].ToString() != null // note that this line makes no sense. If you can call `ToString` on an object, it is not 'null'
}).ToArray();
return bookingupdate;
(Note: I omited the try-block for readability)
You may also want to look into the DataRowExtensions, especially the Field method, to make your code more readable.
回答2:
DataTable.Load(IDataReader)
closes reader after loading data from it. Use DataTable
to get data you loaded.
回答3:
You have already processed the reader at the following line due to which reader is at EOF/Closed
:
dt.Load(rdr);
If you want to process the records after above method call, you should make use of your created DataTable
object dt
by above line unsing for loop with dt.Rows.Count
instead of while (rdr.Read())
Checkout this topic from MSDN
来源:https://stackoverflow.com/questions/14873618/error-invalid-attempt-to-call-read-when-reader-is-closed-after-the-while-loop