MySqlDataReader object not receiving any data from function - c#

I have a post action method which takes in a username and password from a form. In this action method I am using a function to execute a mysql command to a database
This is the function to read from the database
public static MySqlDataReader GetDataFromDB(string command)
{
using (MySqlConnection con = new MySqlConnection(ConStr))
{
com = new MySqlCommand(command, con);
con.Open();
MySqlDataReader rdr1 = com.ExecuteReader();
while (rdr1.Read())
{
}
return rdr1;
}
}
This is how i tried to use this function in my action method
MySqlDataReader rdr2 = Helper.GetDataFromDB("select * from library.Accounts where username = '" + username + "' and password = '" + password + "'");
I put a breakpoint in the helper method and could see that it was reading from the database fine with it storing all the expected row data in the internal 'rdr1' object however it isnt returning anything at the end as the 'rdr2' object is empty once it's finished. I don't know if something is wrong or if im just being an idiot and so i would appretiate if anyone can tell me where im going wrong.

A Data Reader such as MySqlDataReader is Forward Only. This means that once the data has been read and moved on to the next record, or the end of the data, it cannot go back to the beginning.
If you remove this block of code:
while (rdr1.Read())
{
}
You should find it will return the Data Reader at the start, and therefore be able to read the data you loaded from the database.
In addition, you should know that when the using () {...} block finishes the connection will be closed, along with the Data Readers ability to read the data.
If you do want to return the Data Reader, remove the using() {...} block to be a simple statement like:
MySqlConnection con = new MySqlConnection(ConStr);
If you do want to navigate backwards and forwards, filter or sort the data after it has been loaded, you should LOAD the data in to a DataTable from the Data Reader.
Example:
DataTable dt = new DataTable();
dt.Load(rdr1);

Related

Close SqlDataReader if there are no more rows left to read - C#

This is causing me a headache. I know this question (or atleast variants of it) has been asked many times but before one flags it as a duplicate please consider the following code:
string myConnectionString = myConnectionString = ConfigurationManager.ConnectionStrings["DBCS"].ToString();
SqlConnection mySQLConnection;
SqlCommand mySQLCommand;
SqlDataReader mySQLDataReader;
using (mySQLConnection = new SqlConnection(myConnectionString))
{
mySQLCommand = new SqlCommand("SELECT TOP 1 * FROM Table ORDER BY Id DESC", mySQLConnection);
mySQLCommand.Connection = mySQLConnection;
mySQLCommand.Connection.Open();
using(mySQLDataReader = mySQLCommand.ExecuteReader())
{
if (mySQLDataReader.HasRows)
{
if (mySQLConnection.State == ConnectionState.Open)
{
while (mySQLDataReader.Read())
{
//Perform Logic : If the last record being returned meets some condition then call the below method
MethodCalled();
}
}
}
}
MessageBox.Show("Connection state: " + mySQLConnection.State);
}
I would like to find a way to either:
Close the reader after it has finished reading
Break out of the while-loop when it has finished reading and there are no more rows left
But I just keep on getting a SqlException stating the following:
invalid attempt to call read when reader is closed
Just from broad observation, I can trace that error is due to me returning data that contains one row only. The problem is that after it has read that row, the compiler goes back to While(mySQLDataReader.Read()){} and attempts to read through a table that does not contain any rows.
I attempted the following:
Wrapping the ExecuteReader() from the command object in a using block so that it automatically closes the reader and the connection respectively once it has done reading like so:
using(mySQLDataReader = mySQLCommand.ExecuteReader())
{
//Logic performed
}
Just before the closing brace of the while-loop, I tried checking if there are any more rows left/returned from the sql command and breaking out the loop once that condition is satisfied:
if(mySQLDataReader.HasRows == false) //No more rows left to read
{
break; //break out of loop
}
Both attempts were unsuccessful. How can I get around this?
It must be one of the following 3 things:
You're using Read() OUTSIDE the using block. Remember that using block will implicitly call Close and Dispose on your reader. Thus any Read() calls must be placed inside the using block.
The body of your using block is explicitly closing the reader. This seems improbable.
Apparently you have declared your mySQLDataReader at a higher level. It could be that some other (async) code is closing the reader. This also is unlikely. You shouldn't, in most cases, define a DataReader at global level.
Edit
Reading the full code block that you have posted now, I'd suggest a few changes. Can you run the following and tell us if it runs:
using (var mySQLConnection = new SqlConnection(myConnectionString))
{
mySQLCommand = new SqlCommand("SELECT TOP 1 * FROM Table ORDER BY Id DESC", mySQLConnection, mySQLConnection);
mySQLCommand.Connection.Open();
using(mySQLDataReader = mySQLCommand.ExecuteReader())
{
while (mySQLDataReader.Read())
{
//Perform Logic : If the last record being returned meets some condition then call the below method
MethodCalled();
}
}
}
If this version runs fine, we can then dig the problem better.
If there is no data to iterate, while loop will not execute at all. Do you need to check for HasRows as such? Also, you should use CommandBehavior.CloseConnection when you are creating data reader. This will make sure that underlying connection is closed once you have read through it.
Should if call SqlDataReader.HasRows if I am calling SqlReader.Read
SQLDataReader Source Code
using (SqlConnection mySQLConnection = new SqlConnection(myConnectionString))
{
using (SqlCommand mySQLCommand = new SqlCommand("SELECT TOP 1 * FROM Table ORDER BY Id DESC", mySQLConnection))
{
mySQLConnection.Open();
SqlDataReader mySQLDataReader = mySQLCommand.ExecuteReader(CommandBehavior.CloseConnection);
while (mySQLDataReader.Read())
{
//Code logic here
}
// this call to mySQLDataReader.Close(); will close the underlying connection
mySQLDataReader.Close();
}
MessageBox.Show("Connection state: " + mySQLConnection.State);
}

Using sql tableadapters to update database C#

I am building an application for a group of friends and myself to use for DnD sessions. Part of the program involves taking all of the values that are entered for our characters, items, etc and storing them to a database. I have the database built, and am pulling from the database into the program, however I am unable to return data to the database. I have the data coming into a dataset, and all of my edits are affecting the dataset, but I cannot get anything to affect the actual source database tables.
Below I have the button that I intend to use to update items in the characters' packs. I have both dataadapter, and tableadapter methods included that I have tried.
private void btnaddpack_Click(object sender, EventArgs e)
{
if (txtbxpack.Text != "")
{
/*connection.Open();
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "UPDATE Pack SET Item = (#ItemName)" + "WHERE Id = '" + this.lstpack.SelectedValue + "';";
cmd.ExecuteNonQuery();
cmd.Clone();*/
string packitem = txtbxpack.Text; //will take item from an textbox
this.packTableAdapter.Insert(packitem);
this.Validate();
this.packBindingSource.EndEdit();
this.packTableAdapter.Update(this.dnD_MachineDataSet.Pack);
}
PopulatePack();
Here is my populate code in case someone needs that:
private void PopulatePack()
{
using (connection = new SqlConnection(connectionString)) //this is all about opening the connection to the sqldatabase, normally it would need to be closed, but this uses idisposable, so it will close itself
using (SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM Pack", connection))
{
DataTable packtable = new DataTable();
adapter.Fill(packtable);
lstpack.DataSource = packtable;
lstpack.DisplayMember = "Item";
lstpack.ValueMember = "Id";
}
}
As mentioned above, all of the changes are appearing whenever I re-populate the listboxes that draw upon the dataset, hence why this is an issue of trying to get that data back into the source database. I will make the obligatory "I'm relatively new to using databases" statement as it will do no good to pretend that I am an expert.
Thanks.
In the commented code, you would need to do the following:
assign the connection object to the SqlCommand object's Connection
property
pass the item name to your #ItemName parameter
assign a parameter value to the 'Id' column in the WHERE clause
remove, 'cmd.Clone();', and replace with, 'connection.Close();'
Here is what the code should look like:
connection.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = connection;
cmd.CommandText = "UPDATE Pack SET Item = (#ItemName) WHERE Id = #ID;";
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#ItemName", txtbxpack.Text);
cmd.Parameters.AddWithValue("#ID", this.lstpack.SelectedValue);
cmd.ExecuteNonQuery();
connection.Close();

data not being written to local SQL Server database file

I have written that gets data from a sensor, I am trying to write this data to a local SQL Server database file.
Code doesn't produce any errors but the data is not being written to the data table.
I have used the following code: (any suggestions?)
static void Insert(string date, double value, string deviceName)
{
string path = Directory.GetCurrentDirectory();
string filename = path + "\\Database1.mdf";
Console.WriteLine(filename);
string connectionString = "Data Source=(LocalDB)\\v11.0;AttachDbFilename=" + filename + ";Database=Database1";
using (SqlConnection conn = new SqlConnection(connectionString))
try
{
{
conn.Open();
SqlDataAdapter adapter = new SqlDataAdapter();
using (SqlCommand cmd = new SqlCommand("INSERT INTO DataTable VALUES(#Id, #Date, #Value, #Device Name)", conn))
{
num11 += 1;
cmd.Parameters.AddWithValue("#Id", num11);
cmd.Parameters.AddWithValue("#Date", date);
cmd.Parameters.AddWithValue("#Value", value);
cmd.Parameters.AddWithValue("#Device Name", deviceName);
cmd.ExecuteNonQueryAsync();
//rows number of record got inserted
}
conn.Close();
}
}
catch (SqlException es)
{
Console.WriteLine(es);
//Display Error message
}
}
You're calling ExecuteNonQueryAsync to asynchronously insert the record - but you're then closing the connection immediately, while the insert has almost certainly not yet completed.
You should either use the synchronous call instead, or use asynchrony properly - probably making the method asynchronous, and awaiting the result of ExecuteNonQueryAsync. You need to wait for the operation to complete before you close the connection, basically.
You don't need to call Close explicitly at all, by the way - you've already got a using statement, so the connection will be disposed as execution exits the block. (It's not clear why you've got an extra block inside the using statement either, by the way.)

SSIS Script Component Closing Reader

I am having an issue with my SSIS Script Component. It seems that my Reader is getting closed before my CreateNewOutputRows method gets a hold of it. Would anyone be able to help me out?
OdbcConnection odbcConn;
OdbcCommand odbcCmd;
OdbcDataReader odbcReader;
public override void PreExecute()
{
base.PreExecute();
using (odbcConn = new OdbcConnection(this.Connections.InformixODBC.ConnectionString))
{
odbcConn.Open();
string cmdText = Variables.INFORMIXQUERY;
cmdText = cmdText.Replace("{{START_DATETIME}}", "'" + Variables.STARTDATETIME + "'");
cmdText = cmdText.Replace("{{END_DATETIME}}", "'" + Variables.ENDDATETIME + "'");
odbcCmd = new OdbcCommand(cmdText, odbcConn);
odbcReader = odbcCmd.ExecuteReader();
}
}
This is how I have the reader currently set up. I stepped through and it seems to exit out of the PreExecute method and go into the CreateNewOutputRows method, but I cant do any of my AddRow calls because the reader is closed.
Any help would be much appreciated. Thanks!
A Reader is a connected via your Connection. The Connection is disposed of once the using statement goes out of scope and voila, your reader is now disconnected from the source.
Instead, you'd need to load your results into a DataSet/DataTable in your PreExecute and then enumerate the results whenever you're ready.
That or push your PreExecute logic into the CreateNewOutputRows method.
MSDN Links for working with ResultSet and filling a DataSet
http://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx
http://msdn.microsoft.com/en-us/library/bh8kx08z(v=vs.110).aspx

Retrieve & update 20000 data records stops working

I am using the following code do get all data records from a MS SQL database and I try to update every single record. The code is used in a WebService. The issue is, that the code runs fine if I have 1000 data records but now I have 20000 data records an the code first returned with an timeout. Then I set the cmd.CommandTimeout to zero to have no timeout. Now when I invoke the function in the IE WebSvc the IE window is still blank and still try to load something but nothing happens. Only 150 datarecords are updated.
Do you have any idea where the issue might be ? Is the code not the best, so what should I change ?
Thank you very much!
WorldSignia
MyCode:
private string AddNewOrgBez()
{
try
{
SqlConnection sqlconn = new SqlConnection(this.connectionString);
SqlCommand cmd;
SqlDataReader reader;
sqlconn.Open();
cmd = new SqlCommand("SELECT * FROM dbo.mydata", sqlconn);
cmd.CommandTimeout = 0;
reader = cmd.ExecuteReader();
while (reader.Read())
{
// Felder holen
string okuerzel = reader["O_KURZ"].ToString();
string bezeichnung = reader["O_BEZ"].ToString();
string[] lines = CreateNewOrgBez(bezeichnung);
string sqlcmd = "UPDATE dbo.mydata SET WEB_OBEZ1 = '" + lines[0] + "', WEB_OBEZ2 = '" + lines[1] + "', WEB_OBEZ3 = '" + lines[2] + "' WHERE O_KURZ = '" + okuerzel + "'";
SqlConnection sqlconn2 = new SqlConnection(this.connectionString);
sqlconn2.Open();
SqlCommand cmd2 = new SqlCommand(sqlcmd, sqlconn2);
cmd2.CommandTimeout = 0;
cmd2.ExecuteNonQuery();
sqlconn2.Close();
}
reader.Close();
sqlconn.Close();
return "OK";
}
catch (Exception ex)
{
return ex.Message;
}
}
You are leaking every SqlCommand here - I suggest you review your use of SqlClient classes to find the ones that are IDisposable and restructure your code to ensure they are always freed, using the using construct.
For example, this ensures Dispose gets called even if there is an exception in the bracketed code:
using (SqlCommand cmd2 = new SqlCommand(sqlcmd, sqlconn2))
{
cmd2.CommandTimeout = 0;
cmd2.ExecuteNonQuery();
}
Using a new SqlConnection for every UPDATE is expensive too, this should be done outside the loop. Redundant connection establishment is likely the explanation for your timeout.
Take note of #ck's comment that for efficiency this type of piecemeal client-side operation is not as good as doing the heavy lifting server-side. You should be able to get this code working better, but that does not mean it's the ideal/fastest solution.
I found the issue.
You need first to get all the data records, for example in a new DataTable. The structure I used does not work, because it reads data from the database and also updates the database. After changing it to a new structure it works.
You were using two different connections to read and to update, and one of them was blocking another. This is why when you read all your data first, it began to work.
I doubt if your running into OutOfMemoryException. Can you profile your application and check the memory usage?
Since you are just overwriting the variables in While loop, why don't you try taking them out of the loop.

Categories