I have this code that counts the number of records with the same year and date. But when I run the application it doesn't work. Here is my code:
try
{
string query = "SELECT * FROM tblOrder WHERE dateTime_coded=#dateTimeNow";
MySqlCommand cmd = new MySqlCommand(query, con);
cmd.Parameters.AddWithValue("#dateTimeNow", Convert.ToDateTime(DateTime.Now).ToString("yyyy-MM"));
MySqlDataReader dr = cmd.ExecuteReader();
MessageBox.Show("OK");
con.Open();
while (dr.Read())
{
count++;
}
dr.Close();
con.Close();
}
catch (Exception)
{
}
First you have an empty catch block which makes no sense
Atleast this would have been better
catch (Exception ex)
{
MessageBox(ex.Message);// you would know if in case it failed
}
Now the problem seems to be
MySqlDataReader dr = cmd.ExecuteReader();
MessageBox.Show("OK");
con.Open(); <--- opening after executing the reader !
you should try putting the connection in a using block
using(MySqlConnection con = new MySqlConnection())
{
//your stuff in here
}
Another observation
cmd.Parameters.AddWithValue("#dateTimeNow", Convert.ToDateTime(DateTime.Now).ToString("yyyy-MM"))
DateTime.Now is DateTime no need to Convert it again
A better approach to your problem is through ExecuteScalar (link for SqlServer but it is the same for MySql) and using the COUNT function
using(MySqlConnection con = new MySqlConnection("your_connection_string_here"))
{
con.Open();
string query = "SELECT COUNT(*) FROM tblOrder WHERE dateTime_coded=#dateTimeNow";
using(MySqlCommand cmd = new MySqlCommand(query, con))
{
cmd.Parameters.AddWithValue("#dateTimeNow", DateTime.Now.ToString("yyyy-MM");
int count = (int)cmd.ExecuteScalar();
Console.WriteLine("There are " + count.ToString() + " records");
}
}
As you can see, I have removed the try/catch block that is useless here because you don't do anything with the exception. This will stop the program if your query contains a syntax error or you can't establish a connection with the server. So, if a try/catch is really needed depends on your requirements
(Added also the observation on the DateTime.Now from V4Vendetta)
You can SELECT COUNT(*) FROM ... and then use cmd.ExecuteScalar() to retrieve the count returned.
Related
I have a Data-table with all the mandatory fields which is required by select query in it. Now i am fetching data from 1st row of the data-table and running a select query (as given below). For the first time its working fine.
Now I am taking the 2nd row and giving all the mandatory fields (as i did for the first) and running the select query its giving error "insufficient permissions". When i am running both the select query (which are actually same but with different parameter) manually in Oracle SQL Developer its working fine.
Query1: select cloumnname1 from table where columnname2='valueA' and columnname3= 'VALUEB'
Query2: select cloumnname1 from table where columnname2='valueA' and columnname3= 'VALUEB'
To fetch data from database
public OracleDataReader ExecuteReader(string SelectQuery, string conString)
{
try
{
OpenDbConnection(conString);
OracleCommand cmd = new OracleCommand();
cmd.Connection = con;
cmd.CommandText = SelectQuery;
cmd.CommandType = System.Data.CommandType.Text;
OracleDataReader ora_dataReader = cmd.ExecuteReader();
return ora_dataReader;
}
catch (Exception ex)
{
throw ex;
}
finally
{
}
}
EDIT:
Forgot to mention that i am calling this funtion in another function as given below
public DataTable GetDataFromDB(string SelectQuery, string conString)
{
try
{
DataTable dt = new DataTable();
dt.Load(ExecuteReader(SelectQuery,conString));
return dt;
}
catch (Exception ex)
{
throw ex;
}
finally
{
CloseDbConnection();
}
}
You need to open and close the connection after each query execution.
And also return the OracleDataReader after you have closed the connection or else it would lead to memory leak. If you return the OracleDataReader before you close connection, you would get the same error.
Try something like this:
public OracleDataReader ExecuteReader(string SelectQuery, string conString)
{
try
{
OpenDbConnection(conString);
OracleCommand cmd = new OracleCommand();
con.Open();
cmd.Connection = con;
cmd.CommandText = SelectQuery;
cmd.CommandType = System.Data.CommandType.Text;
OracleDataReader ora_dataReader = cmd.ExecuteReader();
}
catch (Exception ex)
{
Logging.LogMessage(Logging.LogLevel.Error, 0, "DAL", this.GetType().Name, ex.Message + " : " + ex.StackTrace);
throw ex;
}
finally
{
con.close();
con.Dispose();
}
return ora_dataReader;
}
More info in this reference: https://msdn.microsoft.com/en-us/library/system.data.oracleclient.oracledatareader(v=vs.110).aspx
You need to close the database connection and open it again before firing up your second query.
something like:
SqlConnection.Open();
And
SqlConnection.Close();
You need to ensure you're closing both the Connection and DataReader objects.
Try using the CommandBehavior argument in ExecuteReader, as it will close the connection automatically once you close the DataReader.
cmd.ExecuteReader(CommandBehavior.CloseConnection)
I'm trying to write a method to check if a table exists. I am trying to use the using statement to keep it consistent through my database.
public void checkTableExists()
{
connectionString = #"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\keith_000\Documents\ZuriRubberDressDB.mdf;Integrated Security=True;Connect Timeout=30";
string tblnm = "BasicHours";
string str = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = " + tblnm + ");";
SqlDataReader myReader = null;
int count = 0;
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand(str, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
MessageBox.Show("The count is " + count);
myReader = command.ExecuteReader();
while (myReader.Read())
{
count++;
}
myReader.Close();
MessageBox.Show("Table Exists!");
MessageBox.Show("The count is " + count);
}
connection.Close();
}
}
}
catch (SqlException ex)
{
MessageBox.Show("Sql issue");
}
catch (Exception ex)
{
MessageBox.Show("Major issue");
}
if (count > 0)
{
MessageBox.Show("Table exists");
}
else
{
MessageBox.Show("Table doesn't exists");
}
}
It throws an exception when it hits the try block. It catches in the SqlException block.
This is the point where I am learning to interact with databases again. The solution would be good, but more importantly, a brief explanation of where I have need to learn how to improve my code.
Thanks
Keith
Your code fails because when you write directly a query searching for a string value then this value should be enclosed in single quotes like 'BasicHours'.
However there are some improvements to apply to your actual code.
First, you can use a simplified sql command.
Second, you use parameters instead of string concatenations.
SqlCommand cmd = new SqlCommand(#"IF EXISTS(
SELECT 1 FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #table)
SELECT 1 ELSE SELECT 0", connection);
cmd.Parameters.Add("#table", SqlDbType.NVarChar).Value = tblName;
int exists = (int)cmd.ExecuteScalar();
if(exists == 1)
// Table exists
This command text don't require you to use an SqlDataReader because the query returns just one row with one 'column' and the value of this single cell is either 1 or 0.
A lot less overhead.
A part from this, it is of uttermost importance, that you never build sql queries concatenating strings. This method is well know to cause problems.
The worse is called SQL Injection and could potentially destroy your database or reveal confidential information to hackers. The minor ones are crashes when the string concatenated contains single quotes. Use always a parameterized query.
I have used the following code in my project and worked for me:
try
{
using (con = new SqlConnection(Constr);)
{
con.Open();
string query = $"IF EXISTS (SELECT * FROM sys.tables WHERE name = '{tableName}') SELECT 1 ELSE Select 0;"
Exists = int.Parse(sqlQuery.ExecuteScalar().ToString())==1;
con.Close();
}
}
catch{}
The problem could be the line: string tblnm = "BasicHours";. You table name is a string and should be apostrophed, try this: string tblnm = "'BasicHours'";
Inside catch blocks you could also log exception messages and details.
Thanks for the help on this issue. This is the solution that I'm implemnenting.
public void checkTableExists()
{
connectionString = #"
Data Source=(LocalDB)\MSSQLLocalDB;
AttachDbFilename=C:\Users\keith_000\Documents\ZuriRubberDressDB.mdf;
Integrated Security=True;
Connect Timeout=30";
string tblName = #"BasicHours";
string str = #"IF EXISTS(
SELECT 1 FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #table)
SELECT 1 ELSE SELECT 0";
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand(str, connection))
{
connection.Open();
SqlCommand cmd = new SqlCommand(str, connection);
cmd.Parameters.Add("#table", SqlDbType.NVarChar).Value = tblName;
int exists = (int)cmd.ExecuteScalar();
if (exists == 1)
{
MessageBox.Show("Table exists");
}
else
{
MessageBox.Show("Table doesn't exists");
}
connection.Close();
}
}
}
catch (SqlException ex)
{
MessageBox.Show("Sql issue");
}
catch (Exception ex)
{
MessageBox.Show("Major issue");
}
}
When I am reading data from a sql db and want to add all the items into a list (ie. eonumlist) below. Do I need to specifically assign each field or can I mass assign this data? I'm doing this for a report and want to get the data quickly. Maybe I should use a dataset instead. I have 40+ fields to bring into the report and want to do this quickly. Looking for suggestions.
public static List<EngOrd> GetDistinctEONum()
{
List<EngOrd> eonumlist = new List<EngOrd>();
SqlConnection cnn = SqlDB.GetConnection();
string strsql = "select distinct eonum " +
"from engord " +
"union " +
"select 'zALL' as eonum " +
"order by eonum desc";
SqlCommand cmd = new SqlCommand(strsql, cnn);
try
{
cnn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
EngOrd engord = new EngOrd();
engord.EONum = reader["eonum"].ToString();
engord.Name = reader["name"].ToString();
engord.Address = reader["address"].ToString();
eonumlist.Add(engord);
}
reader.Close();
}
catch (SqlException ex)
{
throw ex;
}
finally
{
cnn.Close();
}
return eonumlist;
}
I do something similar storing data from a db into a combo box.
To do this i use the following code.
public static void FillDropDownList(System.Windows.Forms.ComboBox cboMethodName, String myDSN, String myServer)
{
SqlDataReader myReader;
String ConnectionString = "Server="+myServer+"\\sql2008r2;Database="+myDSN+";Trusted_Connection=True;";
using (SqlConnection cn = new SqlConnection(ConnectionString))
{
cn.Open();
try
{
SqlCommand cmd = new SqlCommand("select * from tablename", cn);
using (myReader = cmd.ExecuteReader())
{
while (myReader.Read())
{
cboMethodName.Items.Add(myReader.GetValue(0).ToString());
}
}
}
catch (SqlException e)
{
MessageBox.Show(e.ToString());
return;
}
}
}
This connects to the database and reads each record of the table adding the value in column 0 (Name) to a combo box.
I would think you can do something similar with a list making sure the index values are correct.
Store the data as xml, then deserialize the xml to the list.
I want to sum amount value in the income table where a date is been entered from a textbox.
try
{
con.Open();
SqlDataReader myReader = null;
SqlCommand cmd = new SqlCommand("select sum(amount) from income where date='" + TextBox15.Text + "'", con);
myReader = cmd.ExecuteReader();
while (myReader.Read())
{
TextBox16.Text = (myReader["amount"].ToString());
}
con.Close();
}
catch (Exception e1)
{
Label1.Text = e1.Message;
}
My amount data type is decimal
I don't see any reason to use ExecuteReader in your case. Use ExecuteScalar instead which is exactly you need because your query returns only one column with one row.
Executes the query, and returns the first column of the first row in
the result set returned by the query.
And you should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
For example;
SqlCommand cmd = new SqlCommand("select sum(amount) from income where date = #date", con);
cmd.Parameters.AddWithValue("#date", TextBox15.Text);
TextBox16.Text = cmd.ExecuteScalar().ToString();
First of all user parametrized queries to avoid SQL injection attacks.
There is no column amount in your result, either add alias to your aggregation result or just return first value from reader.
try
{
con.Open();
SqlDataReader myReader = null;
SqlCommand cmd = new SqlCommand("select sum(amount) from income where date = #date", con);
cmd.Parameters.AddWithValue("#date", TextBox15.Text);
myReader = cmd.ExecuteReader();
if (myReader.Read())
{
TextBox16.Text =myReader[0].ToString();
}
con.Close();
}
catch (Exception e1)
{
Label1.Text = e1.Message;
}
Also change while to if because only one result will be returned.
Problem: there is no column amount.
so use alias as below:
Example:
select sum(amount) as totalamount from income where date=#datevalue
=>to avoid sql injection attacks use parameterised queries:
Complete Solution: Change You code as below:
try
{
con.Open();
SqlDataReader myReader = null;
SqlCommand cmd = new SqlCommand("select sum(amount) as totalamount from income where date=#datevalue", con);
cmd.Parameters.Add(new SqlParameter("#datevalue", TextBox15.Text));
myReader = cmd.ExecuteReader();
while (myReader.Read())
{
TextBox16.Text = (myReader["totalamount"].ToString());
}
con.Close();
}
catch (Exception e1)
{
Label1.Text = e1.Message;
}
Why don't you simply do this:
try
{
con.Open();
SqlCommand cmd = new SqlCommand("select isnull(sum(amount),0) from income where date = #date", con);
cmd.Parameters.AddWithValue("#date", TextBox15.Text);
TextBox16.Text = cmd.ExecuteScalar().ToString();
con.Close();
}
catch (Exception e1)
{
Label1.Text = e1.Message;
}
If you can find the time, try giving your objects some reasonable name, quite unlike TextBox16 ...
First question:
Say I have
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string storedProc = "GetData";
SqlCommand command = new SqlCommand(storedProc, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
return (byte[])command.ExecuteScalar();
}
Does the connection get closed? Because technically we never get to the last } as we return before it.
Second question:
This time I have:
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
int employeeID = findEmployeeID();
connection.Open();
SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
command.CommandTimeout = 5;
command.ExecuteNonQuery();
}
}
catch (Exception) { /*Handle error*/ }
Now, say somewhere in the try we get an error and it gets caught. Does the connection still get closed? Because again, we skip the rest of the code in the try and go directly to the catch statement.
Am I thinking too linearly in how using works? ie Does Dispose() simply get called when we leave the using scope?
Yes
Yes.
Either way, when the using block is exited (either by successful completion or by error) it is closed.
Although I think it would be better to organize like this because it's a lot easier to see what is going to happen, even for the new maintenance programmer who will support it later:
using (SqlConnection connection = new SqlConnection(connectionString))
{
int employeeID = findEmployeeID();
try
{
connection.Open();
SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
command.CommandTimeout = 5;
command.ExecuteNonQuery();
}
catch (Exception)
{
/*Handle error*/
}
}
Yes to both questions. The using statement gets compiled into a try/finally block
using (SqlConnection connection = new SqlConnection(connectionString))
{
}
is the same as
SqlConnection connection = null;
try
{
connection = new SqlConnection(connectionString);
}
finally
{
if(connection != null)
((IDisposable)connection).Dispose();
}
Edit: Fixing the cast to Disposable
http://msdn.microsoft.com/en-us/library/yh598w02.aspx
Here is my Template. Everything you need to select data from an SQL server. Connection is closed and disposed and errors in connection and execution are caught.
string connString = System.Configuration.ConfigurationManager.ConnectionStrings["CompanyServer"].ConnectionString;
string selectStatement = #"
SELECT TOP 1 Person
FROM CorporateOffice
WHERE HeadUpAss = 1 AND Title LIKE 'C-Level%'
ORDER BY IntelligenceQuotient DESC
";
using (SqlConnection conn = new SqlConnection(connString))
{
using (SqlCommand comm = new SqlCommand(selectStatement, conn))
{
try
{
conn.Open();
using (SqlDataReader dr = comm.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
Console.WriteLine(dr["Person"].ToString());
}
}
else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
}
}
catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
if (conn.State == System.Data.ConnectionState.Open) conn.Close();
}
}
* Revised: 2015-11-09 *
As suggested by NickG; If too many braces are annoying you, format like this...
using (SqlConnection conn = new SqlConnection(connString))
using (SqlCommand comm = new SqlCommand(selectStatement, conn))
{
try
{
conn.Open();
using (SqlDataReader dr = comm.ExecuteReader())
if (dr.HasRows)
while (dr.Read()) Console.WriteLine(dr["Person"].ToString());
else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
}
catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
if (conn.State == System.Data.ConnectionState.Open) conn.Close();
}
Then again, if you work for EA or DayBreak games, you can just forgo any line-breaks as well because those are just for people who have to come back and look at your code later and who really cares? Am I right? I mean 1 line instead of 23 means I'm a better programmer, right?
using (SqlConnection conn = new SqlConnection(connString)) using (SqlCommand comm = new SqlCommand(selectStatement, conn)) { try { conn.Open(); using (SqlDataReader dr = comm.ExecuteReader()) if (dr.HasRows) while (dr.Read()) Console.WriteLine(dr["Person"].ToString()); else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)"); } catch (Exception e) { Console.WriteLine("Error: " + e.Message); } if (conn.State == System.Data.ConnectionState.Open) conn.Close(); }
Phew... OK. I got that out of my system and am done amusing myself for a while. Carry on.
Dispose simply gets called when you leave the scope of using. The intention of "using" is to give developers a guaranteed way to make sure that resources get disposed.
From MSDN:
A using statement can be exited either when the end of the using statement is reached or if an exception is thrown and control leaves the statement block before the end of the statement.
Using generates a try / finally around the object being allocated and calls Dispose() for you.
It saves you the hassle of manually creating the try / finally block and calling Dispose()
In your first example, the C# compiler will actually translate the using statement to the following:
SqlConnection connection = new SqlConnection(connectionString));
try
{
connection.Open();
string storedProc = "GetData";
SqlCommand command = new SqlCommand(storedProc, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
return (byte[])command.ExecuteScalar();
}
finally
{
connection.Dispose();
}
Finally statements will always get called before a function returns and so the connection will be always closed/disposed.
So, in your second example the code will be compiled to the following:
try
{
try
{
connection.Open();
string storedProc = "GetData";
SqlCommand command = new SqlCommand(storedProc, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
return (byte[])command.ExecuteScalar();
}
finally
{
connection.Dispose();
}
}
catch (Exception)
{
}
The exception will be caught in the finally statement and the connection closed. The exception will not be seen by the outer catch clause.
I wrote two using statements inside a try/catch block and I could see the exception was being caught the same way if it's placed within the inner using statement just as ShaneLS example.
try
{
using (var con = new SqlConnection(#"Data Source=..."))
{
var cad = "INSERT INTO table VALUES (#r1,#r2,#r3)";
using (var insertCommand = new SqlCommand(cad, con))
{
insertCommand.Parameters.AddWithValue("#r1", atxt);
insertCommand.Parameters.AddWithValue("#r2", btxt);
insertCommand.Parameters.AddWithValue("#r3", ctxt);
con.Open();
insertCommand.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message, "UsingTest", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
No matter where's the try/catch placed, the exception will be caught without issues.
Old thread but still relevant. I arrived here looking for a way out of having a using statement inside of a using statement. I am happy with this, notwithstanding any future insightful comments that change my mind. ;) Conversations here helped. Thanks. Simplified for readability -
public DataTable GetExchangeRates()
{
DataTable dt = new DataTable();
try
{
logger.LogInformation($"Log a message.");
string conStr = _config.GetConnectionString("conStr");
using (SqlCommand cmd = new SqlCommand("someProc", new SqlConnection(conStr)))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection.Open();
dt.Load(cmd.ExecuteReader());
}
return dt;
}
catch (Exception ex)
{
logger.LogError(ex, ex.Message);
}
}