SQL query not getting executed - c#

I'm trying to execute a SQL command that inserts values into the table. The code is as below:
public static bool Add(string username, string friend_username, int status, string msg, string key, string reject_key)
{
using (SqlConnection con = new SqlConnection(Config.ConnectionString))
{
con.Open();
StringBuilder query = new StringBuilder();
query.Append("Insert into friends(username,friend_username,status,msg,date_added,val_key,reject_key)values");
query.Append("(#username,#friend_username,#status,#msg,#date_added,#key,#reject_key)");
using (SqlCommand cmd = new SqlCommand(query.ToString(), con))
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add(new SqlParameter("#username", username));
cmd.Parameters.Add(new SqlParameter("#friend_username", friend_username));
cmd.Parameters.Add(new SqlParameter("#status", status));
cmd.Parameters.Add(new SqlParameter("#msg", msg));
cmd.Parameters.Add(new SqlParameter("#date_added", DateTime.Now));
cmd.Parameters.Add(new SqlParameter("#key", key));
cmd.Parameters.Add(new SqlParameter("#reject_key", reject_key));
cmd.ExecuteNonQuery();
}
}
return true;
}
The 'Add' function gets called here :
private void Process_Approve_Action(int mtype, long groupid, long content_id, string usr)
{
// approval status = 0(
int status = 0;
switch (mtype)
{
case 4: // friend invitation
string request_username = usr;
string friend_username = Page.User.Identity.Name;
//FriendsBLL.Update_Status(request_username, friend_username, 0);
//// also add invited user as their own friend
FriendsBLL.Add(friend_username, request_username, status, "", "", "");
Config.ShowMessageV2(msg, Resources.vsk.message_inbox_06, "Success!", 1); //Friend invitation accepted.
break;
}
I've tried debugging the Add function and the debugger doesn't go past 'cmd.ExecuteNonQuery();' and breaks out
What am I doing wrong here?

Add space before VALUES because you have syntax error in SQL:
query.Append("Insert into friends(username,friend_username,status,msg,date_added,val_key,reject_key) values");

The SqlParameter class has many constructors, but two constructors are well know to cause problems when the parameter value is an integer with a zero value. (And in your example the status variable has a zero value)
The first constructor takes a string and an object, the second one takes a string and an SqlDbType. This scenario leads to the following problem.
If you call the SqlParameter constructor and pass an integer with a value of zero the constructor called is the one that consider your parameter an SqlDbType of value zero. And you end up with a parameter with a NULL value.
If the column of your database doesn't accept a NULL value you have a big time scratching your head to understand why your code fails.
I have started to use always this kind of syntax when adding parameters
cmd.Parameters.Add("#status", SqlDbType.Int).Value = status;
By the way, the MSDN explain it as well

Have a look at this
SQL Insert Query Using C#
Some say you need to open the connection right before execute non query.
Also found that your cmd.Parameters.Add() function is deprecated, use cmd.Parameters.AddWithValue() instead.
Complete doco:
https://msdn.microsoft.com/en-us/library/9dd8zze1(v=vs.110).aspx

Use
cmd.Parameters.Add("#PARAMETERNAME", SqlDbType.VarChar).Value = variableName;
Another possible issue is where your connection string is placed
using(SqlConnection con = new SqlConnection("Your Connection String Here");
NOTE: if you have this kind of code you should no longer be doing the
con.Open() since you already placed it in a using() which indicates that if there's an open connection you use it, if not, open a connection.

Related

Foreach loop with if statement ERROR

So I figured I would paste the whole thing, but the foreach loop section isn't working. This is for an add page, and when I publish it and try to search, this is the error page: https://i.imgur.com/9WYBE4G.png. Also, this is what the add page looks like: http://i.imgur.com/8QkFLzW.png.
Referring to the error page, it says "incorrect syntax near "("". Does anyone know how to fix this?
I did originally not have a space before "VALUES" in the query, so that would've been an issue but it isn't anymore
I believe that the issue lies within the logic, or something very small with the formatting that I'm not aware of
I also did not copy and paste this code - it was given to me like this, and my task is to find out how it works and add comments. I'm also supposed to fix this error, which lies in the foreach loop I believe. I don't know c# well enough to know what the error could be
Added comma before GETDATE()
public void ProcessRequest(HttpContext context)
{
// create new Sql connection
SqlConnection connection = new SqlConnection(Properties.Settings.Default.ConnectionString);
connection.Open();
// insert into query
string query = "INSERT INTO license_info (SoftwareTitle, SoftwareVersion, SoftwareVendor, SoftwareLastUpdate)";
query += " VALUES (";
// first is a true boolean statement
// if bool not first, then false
bool first = true;
// might not need this (foreach loop). if not listed first, add key + -#
foreach (string key in context.Request.Form.AllKeys)
{
// add comma (,) if not first
if (!first)
{
query += ", ";
}
query += "#" + key;
first = false;
}
// if not listed first, apply GETDATE() function
if (!first)
{
query += ", GETDATE());";
}
first = false;
SqlCommand command = new SqlCommand(query, connection);
foreach (string key in context.Request.Form.AllKeys)
{
command.Parameters.AddWithValue("#" + key, context.Request.Form[key]);
}
command.ExecuteNonQuery();
connection.Close();
// end connection
// connection.Close();
// redirect to admin
context.Response.Redirect(Properties.Settings.Default.BaseURL + #"/admin");
}
This can greatly be simplified by using the known form keys to get the values. There is no need for looping or building a dynamic query of any sort.
public void ProcessRequest(HttpContext context)
{
// create new Sql connection
const string query = "INSERT INTO license_info (SoftwareTitle, SoftwareVersion, SoftwareVendor, SoftwareLastUpdate) VALUES (#SoftwareTitle, #SoftwareVersion, #SoftwareVendor, #SoftwareLastUpdate)";
using(SqlConnection connection = new SqlConnection(Properties.Settings.Default.ConnectionString))
using(SqlCommand command = new SqlCommand(query, connection))
{
// todo: Update the SqlDbTypes and length according to your schema
command.Parameters.Add(new SqlParameter("#SoftwareTitle", SqlDbType.VarChar, 200)).Value = context.Request.Form["TitleKey"];
command.Parameters.Add(new SqlParameter("#SoftwareVersion", SqlDbType.VarChar, 200)).Value = context.Request.Form["VersionKey"];
command.Parameters.Add(new SqlParameter("#SoftwareVendor", SqlDbType.VarChar, 200)).Value = context.Request.Form["VendorKey"];
command.Parameters.Add(new SqlParameter("#SoftwareLastUpdate", SqlDbType.DateTime)).Value = DateTime.Now;
connection.Open();
command.ExecuteNonQuery();
}
Also you should use using blocks to wrap the types that implement IDisposable, in this case it will always ensure the database connection is closed even if there is an Exception.

Query returning NULL value

I'm trying to execute a query in C# which sums the view count of a user. I get returned a NULL value. Using the same statement in Server Management Studio gives me the correct result.
here's my code:
public static int Count_views(string username)
{
int views = 0;
StringBuilder query = new StringBuilder();
query.Append("SELECT Sum(views) FROM videos WHERE username = #username");
using (SqlConnection con = new SqlConnection(Config.ConnectionString))
{
con.Open();
using (SqlCommand cmd = new SqlCommand(query.ToString(), con))
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add(new SqlParameter("#username", username));
views = Convert.ToInt32(cmd.ExecuteScalar());
}
}
return views;
}
I have debugged the code and the parameters are correct. I get this error :
System.InvalidCastException: Object cannot be cast from DBNull to other types.
which means I'm getting a Null value in return.
The ConnectionString is alright. Every other function works fine except for this one. can anyone tell me what might me the issue here?
Edit:
Below are the screen shots of what I'm encountering. The first screenshot shows the value "Administrator" is being passed inside the function. the second screenshot shows this value is also in the database.
You can change the SUM query to return 0 instead of NULL:
query.Append("SELECT COALESCE(Sum(views),0) FROM videos WHERE username = #username");
You could also use the as operator to cast it to the desired nullable type:
int? views = cmd.ExecuteScalar() as int?;

Update Data Method in C# for a SQL Server Database

I've just gotten started with creating a simple inventory extension for a web app and I've run into an issue where I'm having trouble updating the rows in a table for values that already exist in the Product column.
The method is pretty similar to the insert data method, which is working so I'm not exactly sure about what is going on. Here's the code that I have:
static void ReplaceInventory(string product, int qty)
{
using (SqlConnection con = new SqlConnection(
"Data Source=TestSQL;Initial Catalog=TestInv;User ID=tester;Password=passwordtest;"))
{
con.Open();
try
{
using (SqlCommand command = new SqlCommand(
"UPDATE Inventory SET Qty = #Qty WHERE Product = #Product", con))
{
command.Parameters.Add(new SqlParameter("#Qty", qty));
command.Parameters.Add(new SqlParameter("#Product", product));
command.ExecuteNonQuery();
}
}
catch
{
Console.WriteLine("Record not updated");
}
con.Close();
}
}
This works however:
static void AddInventory(string product, int qty)
{
using (SqlConnection con = new SqlConnection(
"Data Source=TestSQL;Initial Catalog=TestInv;User ID=tester;Password=passwordtest;"))
{
con.Open();
try
{
using (SqlCommand command = new SqlCommand(
"INSERT INTO Inventory VALUES(#Product, #Qty)", con))
{
command.Parameters.Add(new SqlParameter("Product", product));
command.Parameters.Add(new SqlParameter("Qty", qty));
command.ExecuteNonQuery();
}
}
catch
{
Console.WriteLine("Count not insert.");
}
con.Close();
}
}
Any help or pointers would be much appreciated!
Try setting the command type as Text, before executing the query:
command.CommandType = System.Data.CommandType.Text
Have you debugged your code and checked if the values are passed properly?
Try including the SqlDbType and size.
command.Parameters.Add("#Product",SqlDbType.NVarChar, 20,product);
For implicit conversion, try AddWithValue
command.Parameters.AddWithValue(new SqlParameter("#Qty", qty));
command.Parameters.AddWithValue(new SqlParameter("#Product", product));
According to MSDN:
AddWithValue replaces the SqlParameterCollection.Add method that takes
a String and an Object. The overload of Add that takes a string and an
object was deprecated because of possible ambiguity with the
SqlParameterCollection.Add overload that takes a String and a
SqlDbType enumeration value where passing an integer with the string
could be interpreted as being either the parameter value or the
corresponding SqlDbType value. Use AddWithValue whenever you want to
add a parameter by specifying its name and value.
See this link for reference.
But using command.Parameters.Add is more reliable and safe because the type of the data is defined and the database doesn't need to identify and convert the data being sent.
Figured it out. The "Product" column in the table that I had created in my database was of a "text" data type, and so it wasn't recognizing the "=" as valid in the UPDATE expression. When I swapped the "=" sign out for LIKE the function worked as expected. Thanks for the feedback!

Specific cast is not valid, while retrieving scope_identity

I am getting exception: "Specific cast is not valid", here is the code
con.Open();
string insertQuery = #"Insert into Tender (Name, Name1, Name2) values ('Val1','Val2','Val3');Select Scope_Identity();";
SqlCommand cmd = new SqlCommand(insertQuery, con);
cmd.ExecuteNonQuery();
tenderId = (int)cmd.ExecuteScalar();
In the interests of completeness, there are three issues with your code sample.
1) You are executing your query twice by calling ExecuteNonQuery and ExecuteScalar. As a result, you will be inserting two records into your table each time this function runs. Your SQL, while being two distinct statements, will run together and therefore you only need the call to ExecuteScalar.
2) Scope_Identity() returns a decimal. You can either use Convert.ToInt32 on the result of your query, or you can cast the return value to decimal and then to int.
3) Be sure to wrap your connection and command objects in using statements so they are properly disposed.
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand(sql, connection))
{
connection.Open();
int tenderId = (int)(decimal)command.ExecuteScalar();
}
}
Try this:-
con.Open();
string insertQuery = #"Insert into Tender (Name, Name1, Name2) values ('Val1','Val2','Val3');Select Scope_Identity();";
SqlCommand cmd = new SqlCommand(insertQuery, con);
tenderId = Convert.ToInt32(cmd.ExecuteScalar());
EDIT
It should be this as it is correctly pointed out that scope_identity() returns a numeric(38,0) :-
tenderId = Convert.ToInt32(cmd.ExecuteScalar());
Note: You still need to remove the:-
cmd.ExecuteNonQuery();
Test the following first:
object id = cmd.ExcuteScalar()
Set a break point and have a look at the type of id. It is probably a Decimal and cannot directly be casted to int.
it needs Convert.ToInt32(cmd.ExecuteScalar());

how to update a table using oledb parameters?

I am having a table which has three fields, namely LM_code,M_Name,Desc. LC_code is a autogenerated string Id, keeping this i am updating M_Name and Desc. I used normal update command, the value is passing in runtime but the fields are not getting updated. I hope using oledb parameters the fields can be updated.
Here is my code.
public void Modify()
{
String query = "Update Master_Accounts set (M_Name='" + M_Name + "',Desc='" + Desc + "') where LM_code='" + LM_code + "'";
DataManager.RunExecuteNonQuery(ConnectionString.Constr, query);
}
In DataManager Class i am executing the query string.
public static void RunExecuteNonQuery(string Constr, string query)
{
OleDbConnection myConnection = new OleDbConnection(Constr);
try
{
myConnection.Open();
OleDbCommand myCommand = new OleDbCommand(query, myConnection);
myCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
string Message = ex.Message;
throw ex;
}
finally
{
if (myConnection.State == ConnectionState.Open)
myConnection.Close();
}
}
private void toolstModify_Click_1(object sender, EventArgs e)
{
txtamcode.Enabled = true;
jewellery.LM_code = txtamcode.Text;
jewellery.M_Name = txtaccname.Text;
jewellery.Desc = txtdesc.Text;
jewellery.Modify();
MessageBox.Show("Data Updated Succesfully");
}
This annoyed me, screwy little OleDB, so I'll post my solution here for posterity. It's an old post but seems like a good place.
OleDB doesn't recognize named parameters, but it apparently does recognize that you're trying to convey a named parameter, so you can use that to your advantage and make your SQL semantic and easier to understand. So long as they're passed in the same order, it'll accept a variable as a named parameter.
I used this to update a simple Access database in a network folder.
using (OleDbConnection conn = new OleDbConnection(connString))
{
conn.Open();
OleDbCommand cmd = conn.CreateCommand();
for (int i = 0; i < Customers.Count; i++)
{
cmd.Parameters.Add(new OleDbParameter("#var1", Customer[i].Name))
cmd.Parameters.Add(new OleDbParameter("#var2", Customer[i].PhoneNum))
cmd.Parameters.Add(new OleDbParameter("#var3", Customer[i].ID))
cmd.Parameters.Add(new OleDbParameter("#var4", Customer[i].Name))
cmd.Parameters.Add(new OleDbParameter("#var5", Customer[i].PhoneNum))
cmd.CommandText = "UPDATE Customers SET Name=#var1, Phone=#var2" +
"WHERE ID=#var3 AND (Name<>#var4 OR Phone<>#var5)";
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
}
It may look like an excess of code, and yes you're technically repeating yourself, but this makes it worlds easier when you're playing connect-the-dots later on.....
You are close with the rest of your connection and such, but as you note, doing it with parameterized queries is safer from SQL-Injection...
// Some engines used named parameters, others may not... The "?"
// are "place-holders" for the ordinal position of parameters being added...
String MyQuery = "Update MyTable set SomeField = ?, AnotherField = ? "
+ " where YourKeyField = ?";
OleDbCommand MyUpdate = new OleDbCommand( MyQuery, YourConnection );
// Now, add the parameters in the same order as the "place-holders" are in above command
OleDbParameter NewParm = new OleDbParameter( "ParmForSomeField", NewValueForSomeField );
NewParm.DbType = DbType.Int32;
// (or other data type, such as DbType.String, DbType.DateTime, etc)
MyUpdate.Parameters.Add( NewParm );
// Now, on to the next set of parameters...
NewParm = new OleDbParameter( "ParmForAnotherField", NewValueForAnotherField );
NewParm.DbType = DbType.String;
MyUpdate.Parameters.Add( NewParm );
// finally the last one...
NewParm = new OleDbParameter( "ParmForYourKeyField", CurrentKeyValue );
NewParm.DbType = DbType.Int32;
MyUpdate.Parameters.Add( NewParm );
// Now, you can do you
MyUpdate.ExecuteNonQuery();
Just to add to RJB's answer, it's a little-known fact that OleDb actually DOES accept named parameters. You've just got to declare the parameters in SQL as well.
See: low-bandwidth.blogspot.com.au/2013/12/positional-msaccess-oledb-parameters.html
If you DON'T declare the parameters in SQL, OleDb uses purely positional parameter insertion, and it doesn't matter if the names of the parameters match the SQL, or if parameters are used twice in the SQL - it will just go through and blindly replace any found parameters in the SQL in order from start to end, with those passed.
However if you DO declare the parameters correctly, you get the benefit of named parameters and parameters allowed to be repeated multiple times within the SQL statement.

Categories

Resources