I have a problem where if i search for data via a TextBox and the data doesn't exist in the database i get the error
'Object cannot be cast from DBNull to other types.'
I am trying to make a MessageBox appear to say data doesn't exist and cannot figure out how to do this.
I have tryed using an if statement where if the TextBox equals DBNull then a MessageBox appears. this doesnt work and im not too sure why. The error occurs with me trying to **equal** toDBNull. How do i produce aTextBox` saying data doesnt exist?
{
SqlConnection con = new SqlConnection("***COnString**");
con.Open();
SqlCommand comm = new SqlCommand("SELECT SUM (Total_Hours_Day) FROM Sign_In_Out_Table, User_Table WHERE User_Table.FirstName = '" + Search_Username_Alerts_Admin_txtbox.Text + "' AND Sign_In_Out_Table.eb_number = User_Table.eb_number AND Date between GETDATE()-14 and GETDATE()", con);
decimal TotalHoursFortnight = Convert.ToDecimal(comm.ExecuteScalar());
con.Close();
decimal sum = 0;
sum += Convert.ToDecimal(TotalHoursFortnight);
if (Search_Username_Alerts_Admin_txtbox.Text == DBNull)
{
MessageBox.Show("No Data Exists");
}
else
{
MessageBox.Show(Search_Username_Alerts_Admin_txtbox.Text + ":" + Environment.NewLine + " Hours Worked = " + TotalHoursFortnight, ("Working Info Admin"), MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
My expected result is for a message box to appear saying data doesn't exist if searched for. but if it does the data will show in a message box.
You have 3 cases to implement:
No data at all: check for null
Invalid data, e.g. 1 + 2 + NULL + 3 == NULL: check for DBNull.Value
Valid data, e.g. 1 + 2 + 3 == 6: convert it with a help of Convert.ToDecimal()
Code:
// wrap IDisposable into using
using (SqlConnection con = new SqlConnection("***COnString**")) {
con.Open();
//DONE: Make sql readable
//DONE: Make sql parametrized
//TODO: you may want to change eb_number = eb_number into INNER JOIN
string sql =
#"SELECT SUM (Total_Hours_Day)
FROM Sign_In_Out_Table,
User_Table
WHERE User_Table.FirstName = #prm_FirstName
AND Sign_In_Out_Table.eb_number = User_Table.eb_number
AND Date BETWEEN GETDATE() - 14 AND GETDATE()";
using (SqlCommand comm = new SqlCommand(sql, con)) {
//TODO: Better specify RDBMS type explictly with "comm.Parameters.Add(...)"
comm.Parameters.AddWithValue(
"#prm_FirstName", Search_Username_Alerts_Admin_txtbox.Text);
var result = comm.ExecuteScalar();
if (null == result) { // No Data
MessageBox.Show("No Data Exist");
}
else if (DBNull.Value == result) { // We have the Data and it's RDBMS Null
MessageBox.Show("Data Exist, but not valid.");
}
else { // We have a valid Decimal
Decimal sum = Convert.ToDecimal(result);
//TODO: put the relevant code here
}
}
}
I would use decimal.tryparse to see if data was returned
SqlConnection con = new SqlConnection("***COnString**");
con.Open();
SqlCommand comm = new SqlCommand("SELECT SUM (Total_Hours_Day) FROM Sign_In_Out_Table, User_Table WHERE User_Table.FirstName = '" + Search_Username_Alerts_Admin_txtbox.Text + "' AND Sign_In_Out_Table.eb_number = User_Table.eb_number AND Date between GETDATE()-14 and GETDATE()", con);
string TotalHoursFortnight = (comm.ExecuteScalar()).ToString();
con.Close();
decimal sum = 0;
decimal temp;
if(!decimal.TryParse(TotalHoursFortnight, out temp))
{
MessageBox.Show("No Data Exists");
}
else
{
sum += temp;
MessageBox.Show(Search_Username_Alerts_Admin_txtbox.Text + ":" + Environment.NewLine + " Hours Worked = " + TotalHoursFortnight, ("Working Info Admin"), MessageBoxButtons.OK, MessageBoxIcon.Information);
}
You need check null for query result
var result = comm.ExecuteScalar();
if(result != null){
decimal TotalHoursFortnight = Convert.ToDecimal(comm.ExecuteScalar());
// move remain code to if block
}
And if (Search_Username_Alerts_Admin_txtbox.Text == DBNull) should change to
if (Convert.IsDBNull(Search_Username_Alerts_Admin_txtbox.Text){
}
Related
I'm trying to get if a value already exists in my database for a registration and I've searched everywhere for an answer but I get this error:
" You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near...at line 1".
I don't know what I'm doing wrong...
void Start()
{
linhaConn = "Server=localhost;" +
"Database=jogo;" +
"User ID=root;" +
"Password=;" +
"Pooling=false;" +
"CharSet=utf8";
ConnDatabase(linhaConn);
}
void ConnDatabase(string lConn)
{
conn = new MySqlConnection(lConn);
conn.Open();
print("Conectado");
}
public void InserirDB()
{
ConnDatabase(linhaConn);
txtUser = InpUserCriar.text;
txtEmail = InpEmail.text;
command = new MySqlCommand("select * from jogador where ([email] = '" + txtEmail + "')", conn);
int UserExist = (int)command.ExecuteScalar();
if (UserExist > 0)
{
print("already exists");
}
else
{
print("doesnt exists");
}
conn.Close();
EDIT
I did it! Here is the code:
ConnDatabase(linhaConn);
txtUser = InpUserCriar.text;
txtEmail = InpEmail.text;
string countDataEmail;
command = new MySqlCommand("select count(*) from jogador where email= '" + txtEmail+ "' ;", conn);
countDataEmail = command.ExecuteScalar().ToString();
if (countDataEmail == "0")
{
print("it doesnt exist");
}
else
{
print("email already exists");
}
If you just want to check if they query returns ant row you can use UserExist.HasRows
I just wanted to mention SQL Injection! Whenever dealing with User Input make sure they can't harm or retrieve something from your database. See the example which uses a prepared statement to avoid that.
besides that, are you sure it should be
... where ([email] = some#email.address)
instead of (how I know SQL queries)
... where email = some#email.adddres;
So together it would probably be something like
command = new MySqlCommand("select * from jogador where email = #email;", conn);
command.Parameters.AddWithValue("#email", txtEmail);
commandPrepare();
An error is thrown when there is no data in data base while converting a string value into int.
try {
SqlCommand cmdc = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=1 AND Crdt_typ_id=1", con);
string companya_credit_amount = null, comapnyb_credit_amount = null;
con.Open();
SqlDataReader drc = cmdc.ExecuteReader();
if (drc.HasRows)
{
while (drc.Read())
{
companya_credit_amount = drc[0].ToString();
}
drc.Close();
con.Close();
}
SqlCommand cmdcp = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=2 AND Crdt_typ_id=1", con);
con.Open();
SqlDataReader drcp = cmdcp.ExecuteReader();
if (drcp.HasRows)
{
while (drcp.Read())
{
companyb_credit_amount = drcp[0].ToString();
}
drcp.Close();
con.Close();
}
if (!Page.IsPostBack)
{
int companyA = 0,companyB=0;
if (companya_credit_amount != "") { companyA = Convert.ToInt32(credit_amount.ToString()); }
if (companyb_credit_amount != ""){ companyB = Convert.ToInt32(companyb_credit_amount); }
int total = (companyA+companyB);
count_total_lbl.Text = "Rs." + " " + total.ToString();
count_comapnya_lbl.Text = "Rs." + " " + companya_credit_amount.ToString();
count_companyb_lbl.Text ="Rs."+" "+ companyb_credit_amount.ToString();
}
}
catch(Exception ex) { Label2.Text = ex.ToString(); }
If there is value its working fine.but when there is no value in data base there is an error msg.
System.FormatException: Input string was not in a correct format.
Use IsDBNull to check for null values
Create and destroy all your type instances that implement IDisposable in using blocks. This ensures that connections are always released and resources are cleaned up.
Do not use connections across a class. Create them when needed and then dispose of them. Sql Server will handle connection pooling.
Get the native types directly, not the string equivalent! See changes to GetInt32 instead of ToString on the data reader.
You should refactor this to use SqlParameter's and make the retrieval statement generic OR get both SUM values in 1 sql call.
There is an if (!Page.IsPostBack) statement, if none of this code does anything if it is a postback then check at the top of the page and do not execute the sql statements if it is a postback. Otherwise the code is making (possibly) expensive sql calls for no reason.
try
{
int companyA = 0,companyB=0;
using(var con = new SqlConnection("connectionStringHere"))
{
con.Open();
using(SqlCommand cmdc = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=1 AND Crdt_typ_id=1", con))
using(SqlDataReader drc = cmdc.ExecuteReader())
{
if (drc.Read() && !drc.IsDBNull(0))
companyA = drc.GetInt32(0);
}
using(SqlCommand cmdcp = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=2 AND Crdt_typ_id=1", con))
using(SqlDataReader drcp = cmdcp.ExecuteReader())
{
if (drcp.Read() && !drcp.IsDBNull(0))
companyB = drcp.GetIn32(0);
}
}
// if you are not going to do anything with these values if its not a post back move the check to the top of the method
// and then do not execute anything if it is a postback
// ie: // if (Page.IsPostBack) return;
if (!Page.IsPostBack)
{
int total = (companyA+companyB);
count_total_lbl.Text = "Rs." + " " + total.ToString();
count_comapnya_lbl.Text = "Rs." + " " + companyA.ToString();
count_companyb_lbl.Text ="Rs."+" "+ companyB.ToString();
}
}
catch(Exception ex) { Label2.Text = ex.ToString(); }
Try to replace this
SELECT SUM(Credited_amount)
WITH
SELECT ISNULL(SUM(Credited_amount),0)
Also find one confusing code while converting Credited amount values
if (companya_credit_amount != "") { companyA = Convert.ToInt32(credit_amount.ToString()); }
---------^^^^^
if (companyb_credit_amount != ""){ companyB = Convert.ToInt32(companyb_credit_amount); }
I don't know about your business requirement but What i think Instead of using credit_amount value companya_credit_amount should be use to show value for companyA variable right?
You should do 2 things:
string companya_credit_amount = "", comapnyb_credit_amount = "";
Before assigning the value to these string variable you should check for db null as following:
while (drc.Read())
{
companya_credit_amount = (drc[0] != DbNull.Value) ? drc[0].ToString() : "" ;
}
Similarely
while (drcp.Read())
{
companyb_credit_amount = (drcp[0] != DbNull.Value) ? drcp[0].ToString() : "";
}
Try it.
You need to initialize credit_amount to empty and check if db value is null as shown below:
try {
companya_credit_amount = string.Empty;
companyb_credit_amount = string.Empty;
SqlCommand cmdc = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=1 AND Crdt_typ_id=1", con);
string companya_credit_amount = null, comapnyb_credit_amount = null;
con.Open();
SqlDataReader drc = cmd
c.ExecuteReader();
if (drc.HasRows)
{
while (drc.Read())
{
companya_credit_amount = drcp.IsDBNull(0)?string.Empty:Convert.ToString(drcp[0]);
}
drc.Close();
con.Close();
}
SqlCommand cmdcp = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=2 AND Crdt_typ_id=1", con);
con.Open();
SqlDataReader drcp = cmdcp.ExecuteReader();
if (drcp.HasRows)
{
while (drcp.Read())
{
companyb_credit_amount = drcp.IsDBNull(0)?string.Empty:Convert.ToString(drcp[0]);
}
drcp.Close();
con.Close();
}
if (!Page.IsPostBack)
{
int companyA = 0,companyB=0;
if (companya_credit_amount != "") { companyA = Convert.ToInt32(credit_amount.ToString()); }
if (companyb_credit_amount != ""){ companyB = Convert.ToInt32(companyb_credit_amount); }
int total = (companyA+companyB);
count_total_lbl.Text = "Rs." + " " + total.ToString();
count_comapnya_lbl.Text = "Rs." + " " + companya_credit_amount.ToString();
count_companyb_lbl.Text ="Rs."+" "+ companyb_credit_amount.ToString();
}
}
catch(Exception ex) { Label2.Text = ex.ToString(); }
I tried going through my code for hours trying to see where I went wrong and google doesn't seem to have the answer either.
Basically I am running this code:
public bool LoginRequest(string ReceivedUsername, string ReceivedPassword)
{
bool ValidLogin = false;
try
{
using (SqlConnection myConnection = new SqlConnection(ConnectString))
{
myConnection.Open();
Log.Debug("Succesful sql connection");
SqlCommand userSELECTcom = new SqlCommand("SELECT username,password FROM users;", myConnection);
SqlDataReader reader = userSELECTcom.ExecuteReader();
//verify login
while (reader.Read())
{
CompareUsername = reader["username"].ToString();
ComparePassword = reader["password"].ToString();
Log.Debug(ReceivedUsername + " against " + CompareUsername);
Log.Debug(ReceivedPassword + " against " + ComparePassword);
if (CompareUsername == ReceivedUsername && ComparePassword == ReceivedPassword)
{
ValidLogin = true;
Log.Debug(ReceivedUsername + " has logged in successfully!!!");
myConnection.Close();//close sql conn
reader.Close();//close sqldatareader
return ValidLogin;
}
else if (CompareUsername != ReceivedUsername || ComparePassword != ReceivedPassword)
{
if (!reader.Read())
{
Log.Debug(ReceivedUsername + " has not logged in successfully with password: " + ReceivedPassword);
myConnection.Close();//close sql conn
reader.Close();//close sql data reader
return ValidLogin;
}
}
}
//end of verify sequence
}
}
//logging any login request issues
catch (Exception e)
{
Log.Debug(e);
}
return ValidLogin;
}
I have a logging program set up that tells me everything thats happening as the code gets executed. These lines: " Log.Debug(ReceivedUsername + " against " + CompareUsername);
Log.Debug(ReceivedPassword + " against " + ComparePassword); "
helps me see which row is being checked by the reader. I tried with six rows each with unique usernames and passwords and the result basically shows that only row 1, 3 and 5 is checked by the reader against the input from the user. So if I tried to log in with my client using a username and password from row 2, 4 or 6 I get an error saying my log in failed. Can anyone explain why this happens?
You have an extra Reader.Read() call in your condition where you didn't find the login that time. That's skipping to the next record, then your main loop's Reader.Read() goes to the next.
You don't need to loop like this, though. Build a query that looks for a record by the username. If there are no records, login fails. If there is one, check the password.
You have a 2nd reader.Read() on the if statement inside the while block. That is causing your code to skip a record.
To keep things simple you could directly query from database.
Below is example code to check if the received username and password exists in the db:
string sql = #"SELECT username,password FROM users
WHERE username=#username and password = #password";
SqlCommand userSELECTcom = new SqlCommand(sql, myConnection);
userSELECTcom.Parameters.AddWithValue(#username, ReceivedUsername);
userSELECTcom.Parameters.AddWithValue(#password, ReceivedPassword);
using(SqlDataReader reader = userSELECTcom.ExecuteReader())
{
ValidLogin = reader.HasRows;
}
else if (CompareUsername != ReceivedUsername || ComparePassword != ReceivedPassword)
{
if (!reader.Read()) //remove this condition it will skip the current loop
{
Log.Debug(ReceivedUsername + " has not logged in successfully with password: " + ReceivedPassword);
myConnection.Close();//close sql conn
reader.Close();//close sql data reader
return ValidLogin;
}
}
Having problem reading a value from my table in mysql, is the index value i cant read the value back no matter what. all i get is the initialized value of 0 i dont get any error because it return 0, if i run the query in the database it get the correct value. i tried to use executeScalar() but with the same result .
MySqlConnection conn = new MySqlConnection(MyConString);
ulong ukey=0;
try
{
string sql_users2 = "SELECT `key` FROM `permuser` WHERE `user` = '" + myuser + "' AND `code` = '" + mycode + "'";
MySqlCommand cmdSel2 = new MySqlCommand(sql_users2, conn);
conn.Open();
MySqlDataReader dr2 = cmdSel2.ExecuteReader();
dr2.Read();
ukey = dr2.GetUInt64(dr2.GetOrdinal("key"));
// MessageBox.Show("Sorry " + myuser + " already have access to " + mycode + ",\nIf this is an extension, search for the user which key is " + ukey + " and edit the end date.", "Duplicate User Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
dr2.Close();
dr2.Dispose();
}
catch (MySqlException ex) //catch 2
{
MessageBox.Show("catch ukey\nCan't connect to database\n" + ex.ToString());
}
conn.Close();
conn.Dispose();
You are returning a single value from your query, so you could use directly ExecuteScalar instead of ExecuteReader. (the link point to the description for SqlServer, but it is the same for MySql)
An important question to never forget is the usage of parameters instead of string concatenation.
What happen if your myuser or mycode variables contain a single quote? You get wrong results or syntax errors.
Of course, the main problem is the Sql Injection attack to never understimate.
using(MySqlConnection conn = new MySqlConnection(MyConString))
{
ulong ukey=0;
try
{
string sql_users2 = "SELECT `key` FROM `permuser` WHERE `user` = #usr AND `code` = #code";
MySqlCommand cmdSel2 = new MySqlCommand(sql_users2, conn);
conn.Open();
cmdSel2.Parameters.AddWithValue("#usr", myuser);
cmdSel2.Parameters.AddWithValue("#code", mycode);
object result = cmdSel2.ExecuteScalar();
if(result != null)
ukey = Convert.ToUInt64(result);
}
catch (MySqlException ex) //catch 2
{
MessageBox.Show("catch ukey\nCan't connect to database\n" + ex.ToString());
}
}
also I am a bit perplexed about your usage of UInt64. What kind of datatype is stored in the key column?
way is many simply:
ukey = (uint)dr2[0];
OK I have created a product table [ID, itemCode], a sales table and a view that returns SUM of items in stock. Thing is if the item has not been sold yet, there is no record of it in the view.
I need to check if item is in stock in order to complete further sales etc.
What I have done is this:
string selectSQL = "SELECT [total] FROM [stock] WHERE ([itemCode] = " + TextBoxCode.Text + ")";
SqlConnection con = new SqlConnection(connectionString);
SqlCommand com = new SqlCommand(selectSQL, con);
try
{
con.Open();
object obj = com.ExecuteScalar();
if (obj == null) //(also tried is DBNull)
{
lblStatus.Text = "Does not exist in stock";
}
else
{
sum = com.ExecuteScalar().ToString();
lblStatus.Text = "Items in stock: " + sum;
}
}
catch (Exception err)
{
lblStatus.Text = err.Message;
}
finally
{
con.Close();
}
It works fine when the item actually exists in stock but if there is no record i get the error:
Conversion failed when converting the nvarchar value '1E001' to data type int.
'1E001' is the first itemCode in my stock view but it is irrelevant to the itemCode I am trying to insert.
The problem seems to be in the line:
object obj = com.ExecuteScalar();
I have also tried a
"SELECT COUNT(total) FROM [stock] WHERE ([itemCode] = " + TextBoxCode.Text + ")";
with the same results. I can't get it to work.
If ItemCode is not a number, then you would need to include single-quotes before and after the code that inserts TextBoxCode.Text. Example:
string selectSQL = "SELECT [total] FROM [stock] WHERE ([itemCode] = '" + TextBoxCode.Text + "')";
WARNING: Using this code would leave you wide open for SQL Injection attacks!
A preferred method, using a parameter, would be:
string selectSQL = "SELECT [total] FROM [stock] WHERE ([itemCode] = #ItemCode)";
SqlCommand com = new SqlCommand(selectSQL, con);
com.Parameters.AddWithValue("#ItemCode", TextBoxCode.Text);
And for your question itself, the result of ExecuteScalar will be null (a .NET null condition) if there are no rows in the resultset. This is different than if the first field of the first row of the resultset is a database Null value (DBNull.Value).
To check for both, use:
if (obj == null || obj == DBNull.Value)
Note: You shouldn't need to ExecuteScalar the second time (in the event that it's not null), since you'll already have the results in the obj variable.
try writing your if condition like this
if ((obj == null) || (obj == DBNull.Value))
It looks like you need single quotes around your text like so:
"SELECT COUNT(total) FROM [stock] WHERE ([itemCode] = '" + TextBoxCode.Text + "')";