error with SqlCe Parameters - c#

I have made MANY parameterised queries in my time on this lovely planet, and none have thrown an error like this... WTFudge?!?!
ERROR:
There was an error parsing the query. [
Token line number = 1,
Token line offset = 20,
Token in error = #table ]
Obviously the compiler doesn't like my SQL statement... but I see no problem???
Here is my code.
using (SqlCeConnection con = new SqlCeConnection(_connection))
{
string sqlString = "SELECT #colID FROM #table WHERE #keyCol = #key";
SqlCeCommand cmd = new SqlCeCommand(sqlString, con);
cmd.Parameters.Add(new SqlCeParameter("#table", tableName));
cmd.Parameters.Add(new SqlCeParameter("#colID", columnIdName));
cmd.Parameters.Add(new SqlCeParameter("#keyCol", keyColumnName));
cmd.Parameters.Add(new SqlCeParameter("#key", key));
try
{
con.Open();
return cmd.ExecuteScalar();
}
catch (Exception ex)
{
Console.Write(ex.Message);
throw new System.InvalidOperationException("Invalid Read. Are You Sure The Record Exists", ex);
}
finally
{
if (con.State == ConnectionState.Open)
con.Close();
cmd.Dispose();
GC.Collect();
}
}
as you can see its a VERY simple SQL statement. I though "#table" may have been stupidly reserved or something... so ive tried #tableName, #var, #everything!!! dont know what the problem is.
During debug I checked that there was actually a #table parameter in the SqlCeParameterCollection And it was there. Clear as day!!

Since you are in C# (as opposed to stored procs)
string sqlString = "SELECT " + columnIdName +
" FROM " +tableName "WHERE " + keyColumnName + "= #key";
You will want to verify that columnIdName, tableName, keyColumnName are all restricted to a list of values (or at the very least, restrict the length to, say 50 characters), otherwise this procedure is optimized for insecurity and sql injection attacks.

This affected me too on SqlCe. But in Sql Server and in SqlExpress you can use a paarameter for table name.

Related

How to get LAST_INSERT_ID();

I have looked around and I am still confused on how to get the last inserted ID. I added the statment SELECT LAST_INSERT_ID(); at the end of mysql statement i am executing. I am storing the value in prID = Convert.ToInt32(cmd.ExecuteScalar()); This command is creating two instances in my database. I am pretty sure I need to separate these two statements but unsure how to while still getting the last ID.
try
{
Console.WriteLine("Connecting to MySQL...");
conn.Open();
string sql = "INSERT INTO pull_requests (repoID, branchID, fileID, prStatus, prComments) VALUES (#rID, #bID, #fID, #prS, #prC); SELECT LAST_INSERT_ID();";
MySql.Data.MySqlClient.MySqlCommand cmd = new MySql.Data.MySqlClient.MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("#rID", RI);
cmd.Parameters.AddWithValue("#bID", BI);
cmd.Parameters.AddWithValue("#fID", FI);
cmd.Parameters.AddWithValue("#prS", 0);
cmd.Parameters.AddWithValue("#prC", comment);
prID = Convert.ToInt32(cmd.ExecuteScalar());
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
conn.Close();
You need to only call cmd.ExecuteNonQuery() to execute the insert statement. On the return, the cmd object will have its .LastInsertedId property populated for you.
Like this:
try
{
Console.WriteLine("Connecting to MySQL...");
conn.Open();
string sql = "INSERT INTO pull_requests (repoID, branchID, fileID, prStatus, prComments) VALUES (#rID, #bID, #fID, #prS, #prC);";
MySql.Data.MySqlClient.MySqlCommand cmd = new MySql.Data.MySqlClient.MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("#rID", RI);
cmd.Parameters.AddWithValue("#bID", BI);
cmd.Parameters.AddWithValue("#fID", FI);
cmd.Parameters.AddWithValue("#prS", 0);
cmd.Parameters.AddWithValue("#prC", comment);
cmd.ExecuteNonQuery();
long lastId = cmd.LastInsertedId;
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
conn.Close();
Use the MySqlCommand.LastInsertedId property after executing the query.
Typically, the SELECT last_insert_id() is executed separately, immediately after the INSERT is executed, on the same connection. The result of last_insert_id() is connection specific, so you do not need to worry about other clients "overwriting" yours.
You can even reuse the same command with just cmd.CommandText = "SELECT last_insert_id()";
...but as others have pointed out, and a quick web search has clarified for me, it looks like the MySQL .Net connector you are using already provides that without a second query.

Insert into 2 tables at the same time c#

string sql = "Insert into tbl_borrowed (FirstName,LastName,BookName,Category,DateBorrowed,Time,DateToBeReturned) values (#fname,#lname,#bname,#category,#dborrow,#time,#dreturn)";
string sql2= "Insert into tbl_return (FirstName,LastName,BookName,Category,DateBorrowed,Time) values (#fname,#lname,#bname,#category,#dborrow,#time";
MySqlCommand sda = new MySqlCommand("", conn);
sda.CommandType = CommandType.Text;
sda.CommandText = sql;
sda.Parameters.AddWithValue("#fname", txtfname.Text);
sda.Parameters.AddWithValue("#lname", txtlname.Text);
sda.Parameters.AddWithValue("#bname", txtbook.Text);
sda.Parameters.AddWithValue("#category", cmbcategory.Text);
sda.Parameters.AddWithValue("#dborrow", dateTimePicker1.Value.Date);
sda.Parameters.AddWithValue("#time", this.time.Text);
sda.Parameters.AddWithValue("#dreturn", dateTimePicker2.Value.Date);
MessageBox.Show("Item has been added!");
showlv("Select * from tbl_borrowed", lvborrowed);
showlv2("Select * from tbl_return", rb.lvreturn);
txtfname.Clear();
txtlname.Clear();
txtbook.Clear();
cmbcategory.Clear();
dateTimePicker1.ResetText();
dateTimePicker2.ResetText();
try
{
conn.Open();
sda.CommandText = sql2;
sda.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show("ASDF" + ex);
}
finally
{
conn.Close();
}
I want to insert same values into 2 tables. Im just a beginner, please help me. Bear with me...
ERROR:
In your INSERT query Time is a reserved word and needs to be escaped using backtique like below. BTW, both of your INSERT statement have the same mistake.
Insert into tbl_borrowed (FirstName,LastName,BookName,Category,DateBorrowed,`Time`,DateToBeReturned)
Again, instead of executing multiple INSERT that way it's much better you wrap those queries in a stored procedure and call that procedure from your code. That's way if you needed you can actually have both the INSERT running in the same transaction block by wrapping both of them in a begin trans block.

ExecuteScalar always returns 0

I'm not sure why this is happening. I've seen the same issue online with little help out there to correct it.
When i run my query inside Access i get different values ranging from 0 - 10 but for some reason, it won't return that same value inside my code.
static int OrdersPerHour(string User)
{
int? OrdersPerHour = 0;
OleDbConnection conn = new OleDbConnection(strAccessConn);
DateTime curTime = DateTime.Now;
try
{
string query = "SELECT COUNT(ControlNumber) FROM Log WHERE DateChanged > #" + curTime.AddHours(-1) + "# AND User = '" + User + "' AND Log.EndStatus in ('Needs Review', 'Check Search', 'Vision Delivery', 'CA Review', '1TSI To Be Delivered');";
OleDbCommand dbcommand = new OleDbCommand(query, conn);
dbcommand.Connection.Open();
dbcommand.CommandType = CommandType.Text;
dbcommand.CommandText = query;
OrdersPerHour = (int?)dbcommand.ExecuteScalar();
}
catch (OleDbException ex)
{
}
finally
{
conn.Close();
}
return OrdersPerHour.Value;
}
Do not use string concatenation and the Access syntax to build your sql commands.
Use a simple parameterized query like this
string query = "SELECT COUNT(ControlNumber) FROM Log " +
"WHERE DateChanged > ? AND [User] = ? AND " +
"Log.EndStatus in ('Needs Review', 'Check Search', 'Vision Delivery'," +
"'CA Review', '1TSI To Be Delivered');";
OleDbCommand dbcommand = new OleDbCommand(query, conn);
dbcommand.Parameters.AddWithValue("#p1", curTime.AddHours(-1));
dbcommand.Parameters.AddWithValue("#p2", User);
dbcommand.Connection.Open();
dbcommand.CommandType = CommandType.Text;
OrdersPerHour = (int)dbcommand.ExecuteScalar();
In this way the burden to correctly interpret your value is passed to the Framework code that could format dates, decimals and strings according to your database requirements. By the way this will also prevent Sql Injection
Also, the word USER is a reserved keyword in Access SQL and thus you need to encapsulate it with square brackets
First and most important: Use Parametrized Queries!
Regarding your problem, I suggest you to debug the code:
Get the Commandtext of your "OleDbCommand dbcommand" and manually query to see if you get the same result.
Also, you should put your code within the try catch block, else it does not make sense at all.

Question in error in asp.net c#

i have a question if you please help me i have an error
Must declare the scalar variable
"#Deitails".
and i can not find out whats the problem since i am not aware what Scalar is about
var sqlCon = new
SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
// GET CONFERENCE ROLE ID
SqlCommand cmd = new SqlCommand();
cmd.Connection = sqlCon;
cmd.CommandText = "select Conference_Role_ID from AuthorPaper
where Paper_ID = #PaperId";
cmd.Parameters.AddWithValue("#PaperId",
paperId);
cmd.Connection.Open();
string ConferenceRoleId = cmd.ExecuteScalar().ToString();
cmd.Connection.Close();
cmd.Dispose();
string query2 = #"insert into
ReviewPaper(Overall_Rating,Paper_id,Conference_role_id,Deitails)
values(0,#paperId,#ConferenceRoleId,#Deitails);select
SCOPE_IDENTITY() as RPID";
cmd = new SqlCommand(query2, sqlCon);
cmd.Parameters.AddWithValue("#paperId",
paperId);
cmd.Parameters.AddWithValue("#ConferenceRoleId",
ConferenceRoleId);
string ReviewPaperId;
try
{
cmd.Connection.Open();
ReviewPaperId = cmd.ExecuteScalar().ToString();
cmd.Connection.Close();
}
catch (Exception ee) { throw ee; }
finally { cmd.Dispose(); }
thanks
You have a SQL query with a parameter named Details, but you forgot to add the parameter.
You have a line of code which says
string query2 = #"insert into ReviewPaper(Overall_Rating, Paper_id,
Conference_role_id, Deitails) values (0,#paperId,#ConferenceRoleId,#Deitails);
select SCOPE_IDENTITY() as RPID";
You provide the parameters #paperId, #ConferenceRoleId and #Deitails for the values for the insert statement. Later you specify the value for the first two parameters, but not #Deitails:
cmd.Parameters.AddWithValue("#paperId", paperId);
cmd.Parameters.AddWithValue("#ConferenceRoleId", ConferenceRoleId);
You need to add a similar line to add the value for #Deitails so that SQL server knows what to do with it. The error you are getting is coming from SQL server because by not adding a value for #Deitails in your C# code, it is not being declared for you in the SQL code which is sent to the server.
To answer your other question, 'Scalar' in this case means that the variable #Deitails represents a single value.

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