C# select from SQL Server database - c#

I want to make a extra control in my C# application if the record exist.
I have got the following code - but it keeps returning a result of -1 even though the record does exist in the SQL Server database.
Can someone help me with this? I have added --> for where it went wrong
private void btnVerwijderen_Click(object sender, RoutedEventArgs e)
{
if (autonrTextBox.Text == "")
{
MessageBox.Show("Waarschuwing u kunt geen auto verwijderen indien er GEEN autonr is ingevuld");
}
else
{
--> SqlConnection con = new SqlConnection(#"Data Source=DESKTOP-RSEBNR7;Initial Catalog=AudiDealer;Integrated Security=True");
--> string check = "SELECT autonr FROM auto WHERE autonr =#autonr";
--> SqlCommand command1 = new SqlCommand(check, con);
--> command1.Parameters.AddWithValue("#autonr", autonrTextBox.Text);
con.Open();
int auto = command1.ExecuteNonQuery();
con.Close();
--> X - 1 MessageBox.Show(auto.ToString());
if (auto > 0)
{
try
{
con.Open();
using (SqlCommand command = new SqlCommand("DELETE FROM auto WHERE autonr =" + autonrTextBox.Text, con))
{
command.ExecuteNonQuery();
}
con.Close();
}
catch (SystemException ex)
{
MessageBox.Show(string.Format("An error occurred: {0}", ex.Message));
}
}
else
{
MessageBox.Show("Het opgegeven autonr komt niet voor in de database. controleer deze.");
}
}
}

The ExecuteNonQuery() method doesn't work like you think it does. The return value for this method is the number of rows changed, not anything from the result set. SELECT queries don't change rows, so -1 is the expected result. 0 rows would imply a WHERE clause that matched no rows in an UPDATE, DELETE, or INSERT. -1 is used to indicate a different situation... either a statement that doesn't change rows or a rollback. Check the remarks section in the documentation for the method.
You want to use the ExecuteScalar() method instead.
int auto = -1;
using (var con = new SqlConnection(#"Data Source=DESKTOP-RSEBNR7;Initial Catalog=AudiDealer;Integrated Security=True"))
using (var cmd = new SqlCommand("SELECT autonr FROM auto WHERE autonr =#autonr", con))
{
cmd.Parameters.Add("#autonr", SqlDbType.Int).Value = int.Parse(autonrTextBox.Text);
con.Open();
auto = (int)cmd.ExecuteScalar();
}
Finally... why check before deleting? This is just wasteful. Just issue the DELETE statement. There's no need to do a SELECT first. Your try/catch and the if() checks already handle situations where the record doesn't exist just fine.
int autonr = 0;
if (!int.TryParse(autonrTextBox.Text, autonr))
{
MessageBox.Show("Waarschuwing u kunt geen auto verwijderen indien er GEEN autonr is ingevuld");
}
else
{
try
{
using (var con = new SqlConnection(#"Data Source=DESKTOP-RSEBNR7;Initial Catalog=AudiDealer;Integrated Security=True"))
using (var cmd = new SqlCommand("DELETE FROM auto WHERE autonr = #autonr;", con))
{
cmd.Parameters.Add("#autonr", SqlDbType.Int).Value = autonr;
con.Open();
int result = cmd.ExecuteNonQuery();
if (result <= 0)
{
MessageBox.Show("Het opgegeven autonr komt niet voor in de database. controleer deze.");
}
}
}
catch (SystemException ex)
{
MessageBox.Show(string.Format("An error occurred: {0}", ex.Message));
}
}

Please use ExecuteScalar, ExecuteNonQuery will not return the result.

ExecuteNonQuery return only the the row that was change/add/remove
if you want to know how many you have use in the query Count and get the rows'number
SELECT Count(*) as CountAutonr FROM auto WHERE autonr =#autonr
and then you will get the from the CountAutonr the number of Rows

There're many things wrong in that piece of code, I really recommend you to encapsulate those database queries inside a business class that will connect to the database, retrieve the data and return as a DAO object... but that won't answer your question.
The issue is in the select command execution, ExecuteNonQuery is meant for executing UPDATE, INSERT and DELETE statements, returning the number of affected rows:
con.Open();
**int auto = command1.ExecuteNonQuery();**
con.Close();
You must use ExecuteReader method to retrieve the SELECT results as explained in the following article:
Retrieving Data Using a DataReader

The problem is in command1.ExecuteNonQuery() which returns the number of modified rows. Your query doesn't modify anything but only reads data from database, so the return value will be always -1.
So use ExecuteScalar instead - it will return your autonr value. Just remember to check it for null and cast it to correct type:
int auto = 0;
object result = command1.ExecuteScalar();
if (result != null)
auto = (int)result;

Related

Having troubles with a command's execution

So, basically what I'm doing is, after adding a diagnosis on the TextBox I'm checking if there is a Diagnosis with the same name already. The connection works fine, however, I'm having difficulties with executing the command in this line here:
var count = (int)cmd.ExecuteNonQuery();
Here's the full method
protected void MesmoDiagnostico_ServerValidate(object source, ServerValidateEventArgs args)
{
string connectionString = ConfigurationManager.ConnectionStrings["BDClinica"].ConnectionString;
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand("Select COUNT(*) from Diagnosticos Where Diagnostico_Nome=#Diagnostico_Nome", connection);
connection.Open();
cmd.Parameters.AddWithValue("#Diagnostico_Nome", source);
var count = (int)cmd.ExecuteNonQuery();
if (count > 0)
{
args.IsValid = false;
}
else
{
args.IsValid = true;
}
connection.Close();
}
Am I missing something? Thanks!
According to MSDN, ExecuteNonQuery is for executing catalog or UPDATE/INSERT/DELETE operations and returns the number of rows affected. By using a COUNT, you're still looking for "number of rows" but it's being executed as query, not an update.
Since you only want one piece of data, technically the first column of the first row, you can use ExecutScalar instead.
This is almost the exact code that you need :
SqlConnection con = new SqlConnection(Settings.Default.FrakoConnectionString);
SqlCommand maxcommand = new SqlCommand("SELECT MAX(Counter) AS max FROM ppartikulieren", con);
try
{
con.Open();
max = (int)maxcommand.ExecuteScalar() + 1;
}
catch (Exception ex)
{
MessageBox.Show("Fout bij het plakken:\n" + ex.Message, "Frako planner", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
finally
{
con.Close();
}
you can also use a using statement of course. But the point is that you really need to cast the output of ExecuteScalar.

Displaying an error message during insert execution

How do I display an error message if a student is already assigned with the position currently being inserted into the mysql database, then rollback the transaction?
If a different position is assigned, it should continue to check the next row.
Here is my code for insertion:
conn.Open();
MySqlTransaction mt = conn.BeginTransaction();
try {
for (int cnt = 0; cnt <= lv1.Items.Count - 1; cnt++) {
if (lv1.Items[cnt].SubItems[3].Text == " ")
continue;
string query = "insert into candidate(pid,s_id)values(#pid,#sid)";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.Add(new MySqlParameter("#pid", lv1.Items[cnt].SubItems[0].Text ));
cmd.Parameters.Add(new MySqlParameter("#sid", lv1.Items[cnt].SubItems[2].Text));
cmd.Transaction = mt;
cmd.ExecuteNonQuery();
}
mt.Commit();
} catch (Exception error) {
MessageBox.Show(error.Message);
mt.Rollback();
}
conn.Close();
This is my dummy student table:
This is my dummy position table:
This is my dummy candidate table:
This is my listview control sample:
Don't rely on an exception from the insert statement: if you don't insert anything, there is no need to perform a rollback.
Instead, check to see if the item already exists and only insert if it does not. If you need to tell the user that it already exists, you can show the message box.
For example:
// This is just an example; not sure what exact conditions you need
var cmdExists = new MySqlCommand("SELECT 1 FROM candidate WHERE pid = #pid");
cmdExists.Parameters.Add(new SqlParameter("#pid", lv1.Items[cnt].SubItems[0].Text));
if (cmdExists.ExecuteScalar() == DBNull.Value)
{
string query = "insert into candidate(pid,s_id)values(#pid,#sid)";
...
} else {
MessageBox.Show("some error message that makes sense to your user");
}

SQL rows are not being deleted

So I have this code that is designed to delete a row in mySQL server database judging by what is selected in my list box. Here is the code I have to remove the rows:
private void remove_btn_Click(object sender, EventArgs e)
{
try
{
if (Calls_lsb.SelectedItem == null)
MessageBox.Show("Please select an item for deletion.");
}
else
{
int i = Calls_lsb.SelectedIndex;
if (i > 0)
{
SqlConnection connection = new SqlConnection(//My Connection String);
string sqlStatement1 = "DELETE FROM Records WHERE CallID = #Id";
string sqlStatement2 = "DELETE FROM Calls WHERE CallID = #Id";
connection.Open();
SqlCommand cmd1 = new SqlCommand(sqlStatement1, connection);
cmd1.Parameters.AddWithValue("#Id", Calls_lsb.Items[i]);
cmd1.ExecuteNonQuery();
SqlCommand cmd2 = new SqlCommand(sqlStatement2, connection);
cmd2.Parameters.AddWithValue("#Id", Calls_lsb.Items[i]);
cmd2.ExecuteNonQuery();
connection.Close();
Calls_lsb.Items.Remove(Calls_lsb.Items[i]);
}
else
{
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
I get no exceptions and I have similar code that adds records that works fine. I tried stepping into the code but it all seemed fine. It simply just does not delete the row from the database. It removes the correct item from the list, just not the database.
If anyone could shine some light on this situation that would be great, thanks!
Edit : Ok, I seem to have fixed the problem. I just removed the whole i = selected index stuff and replace the 'Calls_lsb.Items[i]' with '(Calls_lsb.SelectedIndex + 1)'. I don't really understand why I was getting an exception when I tried to add 1 to i as this is basically doing the same thing.
Replace your below line code.
cmd1.Parameters.AddWithValue("#Id", Calls_lsb.Items[i]);
//with
cmd1.Parameters.AddWithValue("#Id", Calls_lsb.Items[i].Value);
and
cmd2.Parameters.AddWithValue("#Id", Calls_lsb.Items[i]);
// with
cmd2.Parameters.AddWithValue("#Id", Calls_lsb.Items[i].Value);

Catch Zero Rows Updated

I have the following code that is clearing the account logout flags for an application we use.
try
{
string connectionString = "Data Source=DBSERVER;Initial Catalog=AbraEmployeeSelfService;Integrated Security=False;user=FOO;pwd=BAR";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand("UPDATE dbo.tUSERS SET UserUnsuccessfulLoginCount = 0, UserLockoutInd = 0 WHERE LEFT(UserAbraSuiteLogicalPrimaryKey, 4) = '" + BadgeNumber + "'", connection))
{
command.ExecuteNonQuery();
connection.Close();
}
}
}
catch (SqlException ex)
{
MessageBox.Show(ex.Message);
}
How can I get this to catch when zero rows are returned?
ExecuteNonQuery will return the number of affected rows. Use that. :)
int nbUpdatedRows;
(...)
nbUpdatedRows = command.ExecuteNonQuery();
(...)
if (nbUpdatedRows == 0) // do stuff
ExecuteNonQuery() method returns the total number of rows effected after executing the command.
From MSDN : ExecuteNonQuery()
Executes a Transact-SQL statement against the connection and returns
the number of rows affected.
You can check its return value to compare with zero.
Try This:
int status = command.ExecuteNonQuery();
if(status==0)
MessageBox.Show("No Rows Updated!");

Create database with variable name in sql server

This must be very simple but I can't figure it out, or maybe it is not possible.
I have the next function:
private static bool createDB(SqlConnection dbConn, string dbName)
{
string sqlString = "CREATE DATABASE #dbname";
using (dbConn)
{
using (SqlCommand cmd = new SqlCommand(sqlString, dbConn))
{
cmd.Parameters.AddWithValue("#dbname", dbName);
cmd.CommandType = CommandType.Text;
dbConn.Open();
try
{
cmd.ExecuteNonQuery();
MessageBox.Show("Se creo la DB");
return true;
}
catch (Exception ex)
{
MessageBox.Show("No se creo la DB");
return false;
}
finally
{
//dbConn.Close();
}
}
}
}
But apparently the #dbname is not getting the value, dbName does gets the name I want when I call it, but the exception says incorrect syntax near '#dbname'.
I'm new to C#, please be nice :) I got this from many other posts with prepared statements, but I couldn't find any with a CREATE DATABASE, but I'm assuming this should be very similar.
You aren't allow to do that. Database names and field names will not work this way.
string sqlString = "CREATE DATABASE " + dbname";
Only parameters are allow. Example
string sqlString = "update test set myField = #myVal"
you can then use
cmd.Parameters.AddWithValue("#myVal", yourVar);
You also don't need to add # in Parameters.AddWithValue as it's just implied already.
You always want to add parameters with Parameters.AddWithValue to avoid people from escaping and performing sql injection.
You don't need to use SqlParameters for this, just add the dbName variable to your command text.
private static bool createDB(SqlConnection dbConn, string dbName)
{
string sqlString = "CREATE DATABASE " + dbname;
using (dbConn)
{
using (SqlCommand cmd = new SqlCommand(sqlString, dbConn))
{
cmd.CommandType = CommandType.Text;
dbConn.Open();
try
{
cmd.ExecuteNonQuery();
MessageBox.Show("Se creo la DB");
return true;
}
catch (Exception ex)
{
MessageBox.Show("No se creo la DB");
return false;
}
finally
{
//dbConn.Close();
}
}
}
}
As a side note I wouldn't put a messagebox (I assume this is test code) in a CRUD method like this not to mention this leaves the db connection open until the messagebox is acknowledged.
If you must "paramertize" the database name, then I'd suggest trying something like this...
string sqlString = string.Format("CREATE DATABASE {0}", dbName.Trim().Replace(" ",""));
It will also help guard against SQL injection, help not prevent, but at least you'd be ok with the littlebobbytables exploits.

Categories

Resources