I am just learning to work with ADO.NET and I seem to have a problem.What I am trying to do is get the data from a table and insert it into a DataTable.Here is my code:
public DataTable GetCategories()
{
SqlConnection connection = null;
SqlDataReader reader = null;
DataTable categories = new DataTable();
try {
connection = new SqlConnection();
connection.ConnectionString = connectionString;
connection.Open();
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "GetCategories";
reader = cmd.ExecuteReader();
categories.Columns.Add("Id", typeof(int));
categories.Columns.Add("CategoryName", typeof(int));
while (reader.Read()) {
int categoryId = (int)reader["Id"];
string categoryName = (string)reader["CategoryName"];
categories.Rows.Add(categoryId , categoryName);
}
}catch(Exception e){
DataTable error = new DataTable();
error.Columns.Add("Error");
error.Rows.Add(e.Message);
return error;
}finally{
connection.Close();
reader.Close();
}
return categories;
}
Here is my SQL query :
CREATE PROCEDURE [dbo].[GetCategories]
AS
SELECT Id , CategoryName
FROM Categories
Where I run this method I get back on reader.Close() an exception that says NullRefferenceException.
What am I doing wrong?
EDIT
I just noticed that reader = cmd.ExecuteReader(); throws an InvalidOperationException.Is this because of the query?
The way you have your code written means that if there's an error creating or connecting to the SqlConnection, your finally block will try to close a reader that hasn't been set yet.
Either check for a null value in the finally block or re-structure your code.
The SqlCommand needs access to the SqlConnection object. E.g.:
SqlCommand cmd = new SqlCommand("dbo.GetCategories", connection)
Also, have a look at the using block - it's a better way to structure your data access code.
You need to check the null reference in you finally block:
finally{
connection.Close();
if (reader != null)
reader.Close();
}
If your SqlConnection throws an exception when connection.Open(), the reader is not initialized and its value is null, so you need to check it in your finally block.
Related
I'm getting an error "not all code paths return a value" in method getdatatoTextbox.
Please help me fix this problem.
private DataTable getdatatoTextbox(int RegistrationId)
{
try
{
SqlConnection con = new SqlConnection("Data Source=.;Initial Catalog=DotNetFunda;User id=sa;Password=sqluser");
con.Open();
SqlCommand sqlcmd = new SqlCommand("Getdatatotextbox", con);
sqlcmd.CommandType = CommandType.StoredProcedure;
sqlcmd.Parameters.AddWithValue("#RegistrationId", SqlDbType.Int).Value = RegistrationId;
DataTable dtdatanew = new DataTable();
SqlDataAdapter da = new SqlDataAdapter(sqlcmd);
da.Fill(dtdatanew);
con.Close();
return dtdatanew;
}
catch (Exception ex)
{
}
finally
{
con.Dispose();
}
}
If the event of an Exception nothing is being returned which is not valid if you have a non void return type in your method. Also never swallow exceptions, its bad practice and when something goes wrong you come back later asking questions on SO with why.
On another note, you should wrap all your Disposables in using blocks. If your query fails your Db connection will remain open the way your code is now, I know you have the dispose in the finally but that wont even compile because you defined it inside your try block.
This would fix the problem and give you an Exception (a good thing) when something unexpected happens. You can handle it outside the method or let it bubble up to the original caller and then do something.
private DataTable getdatatoTextbox(int RegistrationId)
{
using(SqlConnection con = new SqlConnection("Data Source=.;Initial Catalog=DotNetFunda;User id=sa;Password=sqluser"))
using(SqlCommand sqlcmd = new SqlCommand("Getdatatotextbox", con))
using(SqlDataAdapter da = new SqlDataAdapter(sqlcmd))
{
con.Open();
sqlcmd.CommandType = CommandType.StoredProcedure;
sqlcmd.Parameters.AddWithValue("#RegistrationId", SqlDbType.Int).Value = RegistrationId;
DataTable dtdatanew = new DataTable();
da.Fill(dtdatanew);
return dtdatanew;
}
}
I'm trying to fetch a record from the database using a stored procedure, but it returns null in SqlDataReader object.
Here is my code:
public Buybest_Liberary.Data.UserManagement getUser(string email)
{
Buybest_Liberary.Data.UserManagement obj = new Buybest_Liberary.Data.UserManagement();
string conString = #"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\ahmadshair\Documents\Buybest.mdf;Integrated Security=True;Connect Timeout=30";
SqlConnection connection = new SqlConnection(conString);
connection.Open();
SqlCommand _cmd = new SqlCommand("getUserRecord", connection);
_cmd.CommandType = CommandType.StoredProcedure;
_cmd.Parameters.Add("#Email", SqlDbType.NVarChar).Value = email;
SqlDataReader dr = _cmd.ExecuteReader();
if (dr.HasRows)
{
obj.UId = Convert.ToInt32(dr[0]);
obj.Email = dr[1].ToString();
obj.Password = dr[2].ToString();
}
return obj;
}
You need to call dr.Read() before accessing the data! Also: put your disposable objects (SqlConnection, SqlCommand, SqlDataReader) into using(..) { ... } blocks to ensure proper disposal:
public Buybest_Liberary.Data.UserManagement getUser(string email)
{
Buybest_Liberary.Data.UserManagement obj = new Buybest_Liberary.Data.UserManagement();
// You should read the connection string from a config file
// don't specify it explicitly in code!
string conString = ConfigurationManager.ConnectionStrings["-your-connection-string-name-here-"].ConnectionString;
using (SqlConnection connection = new SqlConnection(conString))
using (SqlCommand _cmd = new SqlCommand("getUserRecord", connection))
{
_cmd.CommandType = CommandType.StoredProcedure;
_cmd.Parameters.Add("#Email", SqlDbType.NVarChar).Value = email;
connection.Open();
using (SqlDataReader dr = _cmd.ExecuteReader())
{
// the SqlDataReader could return *multiple* rows - how are you
// going to deal with that? Create an object for each row of data
// and add them to a list to return?
while (dr.Read())
{
obj.UId = Convert.ToInt32(dr[0]);
obj.Email = dr[1].ToString();
obj.Password = dr[2].ToString();
}
dr.Close();
}
connection.Close();
}
return obj;
}
Also: what do you do if your stored procedure returns multiple rows of data? You need to somehow deal with that, too
If I am not mistaken you are missing a dr.Read() to fetch the first record.
HasRows is simply telling you whether or not there are any rows to read, whereas Read() advances the internal cursor to the next row in the data, and incidentally returns False if there are no more rows to read, or True if there was another row available.
We need dr.read()
I'm trying to get the SQL result in a C# string variable or string array. Is it possible? Do I need to use SqlDataReader in some way?
I'm very new to C# functions and all, used to work in PHP, so please give a working example if you can (If relevant I can already connect and access the database, insert and select.. I just don't know how to store the result in a string variable).
This isn't the single greatest example in history, as if you don't return any rows from the database you'll end up with an exception, but if you want to use a stored procedure from the database, rather than running a SELECT statement straight from your code, then this will allow you to return a string:
public string StringFromDatabase()
{
SqlConnection connection = null;
try
{
var dataSet = new DataSet();
connection = new SqlConnection("Your Connection String Goes Here");
connection.Open();
var command = new SqlCommand("Your Stored Procedure Name Goes Here", connection)
{
CommandType = CommandType.StoredProcedure
};
var dataAdapter = new SqlDataAdapter { SelectCommand = command };
dataAdapter.Fill(dataSet);
return dataSet.Tables[0].Rows[0]["Item"].ToString();
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
finally
{
if (connection != null)
{
connection.Close();
}
}
}
It can definitely be improved, but it would give you a starting point to work from if you want to go down a stored procedure route.
Try This:
SqlConnection con=new SqlConnection("/*connection string*/");
SqlCommand SelectCommand = new SqlCommand("SELECT email FROM table1", con);
SqlDataReader myreader;
con.Open();
myreader = SelectCommand.ExecuteReader();
List<String> lstEmails=new List<String>();
while (myreader.Read())
{
lstEmails.Add(myreader[0].ToString());
//strValue=myreader["email"].ToString();
//strValue=myreader.GetString(0);
}
con.Close();
accessing the Emails from list
lstEmails[0]->first email
lstEmails[1]->second email
...etc.,
You could use an SQL Data Reader:
string sql = "SELECT email FROM Table WHERE Field = #Parameter";
string variable;
using (var connection = new SqlConnection("Your Connection String"))
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("#Parameter", someValue);
connection.Open();
using (var reader = command.ExecuteReader())
{
//Check the reader has data:
if (reader.Read())
{
variable = reader.GetString(reader.GetOrdinal("Column"));
}
// If you need to use all rows returned use a loop:
while (reader.Read())
{
// Do something
}
}
}
Or you could use SqlCommand.ExecuteScalar()
string sql = "SELECT email FROM Table WHERE Field = #Parameter";
string variable;
using (var connection = new SqlConnection("Your Connection String"))
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("#Parameter", someValue);
connection.Open();
variable = (string)command.ExecuteScalar();
}
This May help you For MySQL
MySqlDataReader reader = mycommand.ExecuteReader();
while (reader.Read())
{
TextBox2.Text = reader.ToString();
}
For SQL
using (SqlCommand command = new SqlCommand("*SELECT QUERY HERE*", connection))
{
//
// Invoke ExecuteReader method.
//
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
TextBox2.Text = reader.GetString(0);
}
}
Try this:
public string SaveStringSQL(string pQuery, string ConnectionString)
{
var connection = new Conexao(ConnectionString);
connection.Open();
SqlCommand command = new SqlCommand(pQuery, connection.Connection);
var SavedString = (string)command.ExecuteScalar();
connection.Close();
return SavedString;
}
The ExecuteScalar function saves whatever type of data there is on your database - you just have to specify it.
Keep in mind that it can only save one line at a time.
I am trying to either pass a reader by reference or to have one returned. And I am having issues with it on the return.
public static SqlDataReader GetSql(string businessUnit, string taskId)
{
const string connstring = "Connection string";
SqlConnection conn = new SqlConnection(connstring);
SqlCommand command = new SqlCommand();
SqlDataReader reader;
try
{
conn.Open();
command.Connection = conn;
command.CommandType = CommandType.Text;
command.CommandText =
"SELECT * FROM Audits WHERE BusinessUnit = #BU AND TaskID = #TID";
command.Parameters.AddWithValue("#BU", businessUnit);
command.Parameters.AddWithValue("#TID", taskId);
return reader = command.ExecuteReader(CommandBehavior.CloseConnection);
}
catch (Exception ex)
{
return null;
}
finally
{
conn.Close();
}
}
SqlDataReader reader = QaqcsqlLib.GetSql("job", "Task1");
if (reader.HasRows)
{
while (reader.Read())
MessageBox.Show(reader[0].ToString());
}
but I get the following error
Invalid attempt to call HasRows when reader is closed.
Any Ideas?
This is the problem:
finally
{
conn.Close();
}
You're closing the connection before the method returns. The reader isn't going to be able to function without an open connection.
(It's not clear why you've got the reader variable at all, given that you only use it when returning.)
Returning a SqlDataReader in a method which itself opens the connection is generally tricky - because it means you don't have a nice way of closing the connection. Better would be to let the caller pass in the connection, at which point you can have:
using (var connection = new SqlConnection(...))
{
using (var reader = QaqcsqlLib.GetSql(connection, "job", "Task1"))
{
// Use the reader here
}
}
EDIT: As noted by Scott, your use of CommandBehavior.CloseConnection would allow closing the reader to close the connection. However, it makes other things trickier. For example, you'd have to dispose of the connection if an exception occurs (because then the caller won't have a chance), but not otherwise - I still prefer my approach.
John is right about why you are having the problem but you don't need to pass in a connection.
I can see that you are already using the SqlCommand.ExecuteReader(CommandBehavior) overload when you start your reader and passing in CommandBehavior.CloseConnection. However the thing you are doing wrong is you are never disposing of the reader that is returned from your function. Remove the finally block then wrap your returned reader in a using block. This will close the underlying connection for you when you exit the block (becuse you passed in CommandBehavior.CloseConnection)
using(SqlDataReader reader = QaqcsqlLib.GetSql("job", "Task1"))
{
while (reader != null && reader.Read()) //Added null check as your GetSql could return null.
MessageBox.Show(reader[0].ToString());
}
I also stripped out reader.HasRows because it is unnessasary. If no results where returned the first call to reader.Read() will return false and the code inside the while loop will never execute.
You still need to close the connection when a exception occurs but you can just move the close from the finally in to the catch.
catch (Exception ex)
{
conn.Dispose(); //Disposing closes the connection.
return null;
}
you can try follow the next example http://msdn.microsoft.com/en-us/library/haa3afyz.aspx .
You shouldn't call to close method before to use your reader.
Jon Skeet and Scott Chamberlain are both correct. If you wish to keep with your way of structuring the code (as opposed to Jon Skeet's approach), you will need to modify your code so that the connection is closed should an error occur while executing the SqlCommand.
public static SqlDataReader GetSql(string businessUnit, string taskId)
{
const string connstring = "Connection string";
SqlConnection conn = null;
SqlCommand command = null;
SqlDataReader reader = null;
try
{
conn = new SqlConnection(connstring);
command = new SqlCommand();
command.Connection = conn;
command.CommandType = CommandType.Text;
command.CommandText = "SELECT * FROM Audits WHERE BusinessUnit = #BU AND TaskID = #TID";
command.Parameters.AddWithValue("#BU", businessUnit);
command.Parameters.AddWithValue("#TID", taskId);
conn.Open();
reader = command.ExecuteReader(CommandBehavior.CloseConnection);
conn = null;
return reader;
}
catch (Exception ex)
{
return null;
}
finally
{
if (conn != null) conn.Dispose();
if (command != null) command.Dispose();
}
}
string query = "select * from cfo_daily_trans_hist";
try
{
using (SqlConnection connection = new SqlConnection(
cnnString))
{
SqlCommand command = new SqlCommand(query);
command.Connection = connection;
connection.Open();
var result = command.ExecuteReader();
DataTable datatable = new DataTable();
datatable.Load(result);
connection.Close();
}
}
So the var result is created through the ExecuteReader(); and HasRows is true, and it shows the correct amount of fields. However, the DataTable that I create from it is empty.
What am I doing wrong? I'm 99% sure it's getting data, but I don't know how to find it through the SqlDataReader object to make sure.
Thanks.
Instead of a SqlDataReader, use a SqlDataAdapter.
SqlDataAdapter myAdapter = new SqlDataAdapter(command);
myAdapter.Fill(datatable);
With a SqlDataAdapter, you don't need to explicitly call SqlConnection.Open() and SqlConnection.Close(). It is handled in the Fill() method.
You can try to add "COALESCE" in your sql command statement ... if you have some NULL value in your query result, you will have problem with dataTable