I am trying to convert an old project (originally written in VB6) to C#. I came across the following snippet of code (roughly) :
Dim sSql As String
Dim adoRs As ADODB.Recordset
sSql = "EXEC " & PROC_GETEPORTPARAMETERVALUES & " " & iTemplateId & ", " & iViewId & ", " &
g_sTenantSN
Set adoRs = Nothing
' Execute the query
Set adoRs = m_odbcDVConnection.OpenRecordSet(sSql, App.EXEName, Me.Name, csPROC_NAME)
If (adoRs.RecordCount > 0) Then
Do Until (adoRs.EOF)
'Some conditional statements within this block
Loop
End If
After doing some research online, I came up with the following code conversion for C#. I have used SqlConnection here. Eventhough I found that ADODB is available to use for C# as well. But not sure which one to use.
sSql = "EXEC " + PROC_GETEPORTPARAMETERVALUES + " " + iTemplateId + ", " + iViewId + ", " +
GlobalHelper.Tenant;
SqlConnection conn = new SqlConnection(ConfigurationManager.AppSettings["ConnectionString"]);
if (conn.State != ConnectionState.Open)
{
conn.Open();
}
SqlCommand cmd = new SqlCommand(sSql);
cmd.CommandType = CommandType.Text;
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
// Conditional statements
}
I am not entirely sure if the above is a proper converison is proper. But more importantly, I wanted to know when to use ADODB connection and when to use SqlConnection for C# projects.
From my understanding, in the above case, I think both the process executes a SQL command and reads records.
ADODB is not normally used in C#. You should always use SqlClient.
You have a number of issues with your converted code:
You are missing using blocks
No need to, nor should you, inject parameters. Pass them properly using SqlParameter
You should also use CommandType.StoredProcedure, and the command text is then just the procedure name. If you wanted to use Text it is the default, no need to set it.
There is no point checking if the connection is not open, of course it isn't as you just created it
using (SqlConnection conn = new SqlConnection(ConfigurationManager.AppSettings["ConnectionString"]))
using (SqlCommand cmd = new SqlCommand(PROC_GETEPORTPARAMETERVALUES))
{
cmd.CommandType = CommandType.StoredProcedure;
// Specify correct parameter type, add parameter length for strings
cmd.Parameters.Add("#iTemplateId", SqlDbType.NOT_SURE_WHAT_YOU_WANT_HERE).Value = iTemplateId;
cmd.Parameters.Add("#iViewId", SqlDbType.NOT_SURE_WHAT_YOU_WANT_HERE).Value = iViewId;
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
// Conditional statements
}
}
}
Related
I'm trying to get the value of a Field (User Access level it's 1 or 2 in string format) after login
OleDbConnection connection = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=dsms.accdb");
connection.Open();
OleDbDataReader reader = null;
OleDbCommand command = new OleDbCommand("SELECT AL From Users WHERE Username='" + textusername.text + "'", connection);
reader = command.ExecuteReader();
if( reader.HasRows)
{
MessageBox.Show("success","status");
label1.Text = reader.GetString(1);
}
else
MessageBox.Show("failur", "status");
connection.Close();
I did execute the code in Access and it's was totally fine
but in the program, it says "No data exist for the row/column"
The main problem in your code is the fact that you need to call reader.Read() to get anything out from a DataReader. Just calling HasRows doesn't position the reader on the first record of your query.
There are other problems in your code.
Disposable objects like connections, commands and readers should be created in a using statement to ensure proper disposition after use and because you have only one field in your query, you should use the index 0 to retrieve it not 1.
Finally the most important one. You should NEVER concatenate strings to build an sql query. In this way a malicious user could write anything in your textbox, even valid sql commands that could be executed against your database. It is called Sql Injection and if you search for these terms you will find very detailed discussions about it. However, to avoid this problem (and others like parsing input with apostrophes) you use a parameterized query like below.
using(OleDbConnection connection = new OleDbConnection(.....))
using(OleDbCommand command = new OleDbCommand("SELECT AL From Users WHERE Username=#name", connection);
{
connection.Open();
command.Parameters.Add("#name", OleDbType.VarWChar).Value = txtusername.text;
using(OleDbDataReader reader = command.ExecuteReader())
{
if( reader.Read())
{
MessageBox.Show("success","status");
label1.Text = reader.GetString(0);
}
else
MessageBox.Show("failur", "status");
}
}
C#, Razor
my code is:
#using (SqlConnection Praktikum2 = new SqlConnection("Data Source=Mark\\SQLEXPRESS;Initial Catalog=Connection;Integrated Security=True"))
{
using(connection)
{
SqlCommand command = new SqlCommand("SELECT KategoryID FROM Kategory WHERE Name = " + Request.Params["kategory"]);
connection.Open();
SqlDataReader reader = command.ExecuteReader(); //ERROR!!!
while (reader.Read())
{
string ID = reader["KategorieID"].ToString() ;
Console.WriteLine("ID = {0}", ID);
}
reader.Close();
};
}
i get an error that there's a wrong syntax near "=".
how can i solve this?
The problem is caused by the missing quotes around the value passed for your search. You could add a set of single quote before and after the value obtained by the Request but that would be a bigger error and the source of a problem called Sql Injection.
The only way to handle this is to use a parameter query
SqlCommand command = new SqlCommand(#"SELECT KategoryID FROM Kategory
WHERE Name = #name", connection);
command.Parameters.Add("#name", SqlDbType.NVarChar).Value = Request.Params["kategory"];
Also, as noted in another answer, your code seems to not have associated the connection to the command, I think that it is just a typo here because the error message in that case would be 'need an open connection'
You forgot to assign the connection to the command. So when you call ExecuteReader(), it does not know on which connection it should be executed.
You can assign the connection like this:
SqlCommand command = new SqlCommand(
"SELECT KategoryID FROM Kategory WHERE Name = " + Request.Params["kategory"],
connection); // provide connection as second parameter!
or use connection.CreateCommand() to create your command.
Second, you forgot the quotation marks around your string:
"SELECT KategoryID FROM Kategory WHERE Name = '" + Request.Params["kategory"] + "'"
but inserting user data directly into your query opens your code to SQL Injection. Please use parameterized queries instead.
If your kategory column is not of integer data type then you need to surround your value with (') i.e single quote characters
Then your query will be like
SqlCommand command = new SqlCommand("SELECT KategoryID FROM Kategory WHERE Name ='" + Request.Params["kategory"] + "'");
The exception is caused by how you are creating your sql statement. The fix should not be correcting the syntax but using parameters instead. This will prevent sql injection attacks.
Also
You really should not be writting sql in your views, do it in your controller method instead and return the result in the Model to be used in your view. Better yet, abstract it to a different layer and call that layer from your controller. This has to do with SoS (Separation of Concerns), your code will very difficult to maintain if you just write everything into your views.
Wrap your connections, commands, and readers in using blocks.
Modified Code
#{
using(SqlConnection Praktikum2 = new SqlConnection("Data Source=Mark\\SQLEXPRESS;Initial Catalog=Connection;Integrated Security=True"))
using(SqlCommand command = new SqlCommand("SELECT KategoryID FROM Kategory WHERE Name = #name", Praktikum2))
{
command.Parameters.Add(new SqlParameter("#name", SqlDbType.VarChar){ Value = Request.Params["kategory"]});
connection.Open();
using(SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
string ID = reader["KategorieID"].ToString() ;
Console.WriteLine("ID = {0}", ID);
}
}
}
}
How can I add a variable to my SQL string and run it against the server successfully? I want to run this statement through my C#
protected void RunSQLQuery(string salesman, string connectionString)
{
SqlConnection cnn;
SqlCommand cmd;
StringBuilder sql = new StringBuilder();
SqlDataReader reader;
cnn = new SqlConnection(connectionString);
sql = new StringBuilder();
sql.Append("update database ");
sql.Append("set shippdate = GetDate() ");
sql.Append("where salesman = "' + salesman + "'");
sql.Append("and managerapproval is not null ");
cnn.Open();
cmd = new SqlCommand(sql.ToString(), cnn);
reader = cmd.ExecuteReader();
reader.Close();
cmd.Dispose();
cnn.Close
}
This presents multiple compile errors underlining my +salesman+ code. The errors are:
Only assignment, call, increment, decrement, and new object
expressions can be used as a statement
; expected
) expected
Too many characters in character literal Newline in constant
You are not adding the string object that salesman refers, you are adding salesman as a string literal.
Just add it as a parameter like;
var cmd = new SqlCommand("update database set shippdate = GetDate() where salesman = #salesman");
cmd.Parameters.Add("#salesman", salesman);
...
And use ExecuteNonQuery to execute your command, not SqlDataReader. This SqlDataReader is for return some data.
But more important, you should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
Also use using statement to dispose your connection and command automatically instead of calling Close or Dispose methods manually.
As a full example;
protected void RunSQLQuery(string salesman, string connectionString)
{
using(var cnn = new SqlConnection(connectionString))
using(var cmd = cnn.CreateCommand())
{
cmd.CommandText = #"update database set shippdate = GetDate()
where salesman = #salesman";
// I assume your column is nvarchar
cmd.Parameters.Add("#salesman", SqlDbType.NVarChar).Value = salesman;
cnn.Open();
cmd.ExecuteNonQuery();
}
}
For myself, I always prefer to use SqlParameterCollection.Add(string, SqlDbType, Int32) overload to specify my parameter type and it's size but since you never mentioned your salesman column type, I couldn't post this in my example.
As you can also see from the syntax highlighting, the compile errors are caused because you did not escape the quotes properly in sql.Append("where salesman = "' + salesman + "'");.
As a side note, you should never insert strings into sql queries without first validating them, or you are open to sql injection, e.g. if i pass "''; drop table database;" as salesman parameter. It is better to use SqlParameter.
I would suggest using the AddWithValue method from your sql command combined with the UPPER function to make it case insensitive:
SqlCommand cmd = cnn.CreateCommand();
cmd.CommandText = "UPDATE database SET shippdate = GetDate() WHERE UPPER(salesman) = UPPER(#salesMan)";
cmd.Parameters.AddWithValue("#salesMan", salesman);
if (cnn.State.Equals(ConnectionState.Closed))
{
cnn.Open();
}
cmd.ExecuteNonQuery();
cnn.Close();
As mentioned in above answers, yes, writing queries in this way is not a good way to do it. But still if you want to do it that way only, you will have to change:
sql.Append("where salesman = "' + salesman + "'");
to
sql.Append("where salesman = '" + salesman + "'");
I'm trying to make an ATM Simulator. When I want to add some money in my account which is registered in SQL Server, I don't know how to add a value over the old value.
My SQL Table is like this:
Name | Surname | Pin | Money
When i want to add Money from textBox in the Money column I don't know how.
Code:
con.Open();
string connString = "";
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "select * from Useri where Pin='" + textBox1_Pin.Text + "' ";
var reader = cmd.ExecuteReader();
double balanciFillestar = Convert.ToDouble(reader[3]);
double balanciRi = balanciFillestar + double.Parse(textBox_shuma.Text);
cmd.CommandText = "update Useri set Shuma =" + balanciRi + "";
cmd.ExecuteNonQuery();
con.Close();
The most immediate need would be to filter the update statement, so instead of this:
cmd.CommandText = "update Useri set Shuma =" + balanciRi + "";
you really need this:
cmd.CommandText = "UPDATE Useri SET Shuma = #Shuma WHERE Pin = #Pin";
But, before you can do that we really need to refactor it all.
var selectSql = "SELECT Shuma FROM Useri WHERE Pin = #Pin";
var updateSql = "UPDATE Useri SET Shuma = #Shuma WHERE Pin = #Pin";
using (SqlConnection c = new SqlConnection(cString))
{
c.Open();
double balanciFillestar;
using (SqlCommand cmd = new SqlCommand(selectSql, c))
{
cmd.Parameters.AddWithValue("#Pin", textBox1_Pin.Text);
balanciFillestar = Convert.ToDouble(cmd.ExecuteScalar());
}
double balanciRi = balanciFillestar + double.Parse(textBox_shuma.Text);
using (SqlCommand cmd = new SqlCommand(updateSql, c))
{
cmd.Parameters.AddWithValue("#Shuma", balanciRi);
cmd.Parameters.AddWithValue("#Pin", textBox1_Pin.Text);
cmd.ExecuteNonQuery();
}
}
There are a number of things I'm doing here that you'll want to learn from:
The SQL statements are parameterized.
The SqlConnection is not shared.
The ADO.NET objects are wrapped in a using statement.
A SqlDataReader isn't used to get a single value from a single row.
All of these things, with the exception of #4, are equally important.
Point #1 ensures that you're protecting yourself from SQL Injection attacks.
Point #2 is quite simply the only viable way to use the class. It's meant to be constructed, opened, used, and disposed.
Point #3 ensures that the Dispose method is called on all of the objects. This is extremely important with these classes because they implement IDisposable. They do because they handle unmanaged resources (i.e. a connection to a SQL server).
Point #4 is really just an optimization. Data readers are meant for reading very large data sets, one row at a time, to gain performance and resource management. Likewise the data reader is actually left open until it is closed or disposed. Generally speaking there are almost always better API's to use than a data reader unless using it for their express purpose.
Your code is vulnerable against SQL injection. Please consider this and use parameterized query.
string ps= "update Useri set Shuma = Shuma + #shuma WHERE Pin= #pin";
SqlCommand cmd = new SqlCommand(ps, c);
cmd.Parameters.AddWithValue("#shuma", textBox_shuma.Text);
cmd.Parameters.AddWithValue("#pin", textBox1_Pin.Text);
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.