I am trying to update a single value into my access .accdb database via a c# winform interface. my SQL statement is:
updateString("UPDATE Password_Table SET Password = '" + confirmnewpasswordTextBox.Text + "' WHERE Password_ID = 'user'");
field-wise it should be correct but whenever i execute the updateString function it only returns zero. may I know what I am doing wrongly in the following example?
public static bool updateString(string SQL)
{
using (var connection = new OleDbConnection(connectionString))
using (var command = connection.CreateCommand())
{
connection.Open();
command.CommandText = SQL;
command.CommandType = CommandType.Text;
try
{
return command.ExecuteNonQuery();
}
catch
{
return -1;//for error
}
}
}
Thank you!!
update:
System.Data.OleDb.OleDbException: Syntax error in UPDATE statement.
hmmm, i still cant figure out what is wrong, my table is Password_Table, and I am trying to update a column called Password where the Password_ID is "user".
update: found the error! turns out that Password is like a restricted keyword and i had to cover it in [ ] before it could work..
There are serious issues with your code. It is vulnerable to SQL injection. You should always use parametrized queries to avoid that. For example:
public static string UpdatePassword(string user, string password)
{
using (var connection = new OleDbConnection(connectionString))
using (var command = connection.CreateCommand())
{
connection.Open();
command.CommandText = "UPDATE Password_Table SET Password = #pwd WHERE Password_ID = #user";
command.Parameters.AddWithValue("#pwd", password);
command.Parameters.AddWithValue("#user", user);
try
{
return command.ExecuteNonQuery();
}
catch
{
return -1;//for error
}
}
}
And then invoke like this:
int rowsAffetected = UpdatePassword("user", confirmnewpasswordTextBox.Text);
Now, if this returns 0 it means that there is no record in your database which matches the Password_ID = user condition and there is nothing to update.
Related
Can someone tell my why my expectedNumber reader throws an error
The name reader does not exist in its current context
As far as I can see all this is doing is reading the first row and first column, don't understand why the reader is throwing a tantrum.
It doesn't like the line:
ExpectedNumber = reader.GetInt16(0);
The query is :
SELECT TOP (1) [ExpectedNumber]
FROM [dbo].[MyDatabase]
WHERE id = '{0}'
Code:
try
{
using (SqlCommand cmd = new SqlCommand(string.Format(Query, id), Connection))
{
Connection.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
// Check is the reader has any rows at all before starting to read.
if (reader.HasRows)
{
int ExpectedNumber = 0;
// Read advances to the next row.
while (reader.Read() == true)
{
// To avoid unexpected bugs access columns by name.
ExpectedNumber = reader.GetInt16(0);
}
Connection.Close();
return ExpectedResult;
}
Assert.Fail("No results returned from expected result query");
return 0;
}
}
}
catch (Exception e)
{
Connection.Close();
throw;
}
You should escape your query parameters, otherwise your code is vulnerable to SQL injection attacks, also, by using command parameters as in the example below you can make sure you are using the right data type (it seems you are trying to pass an int id as a string).
You are just trying to get one value so you don't need to use a reader and can use ExecuteScalar instead.
Finally, you don't need to handle closing the connection if you enclose it in a using block so you can avoid the try catch block as well.
string query = "SELECT TOP (1) [ExpectedNumber] FROM [dbo].[MyDatabase] WHERE id = #id";
using (var connection = new SqlConnection("connStr"))
{
connection.Open();
using (var cmd = new SqlCommand(query, connection))
{
cmd.Parameters.Add("#id", SqlDbType.Int).Value = id;
object result = cmd.ExecuteScalar();
if (result != null && result.GetType() != typeof(DBNull))
{
return (int)result;
}
Assert.Fail("No Results Returned from Expected Result Query");
return 0;
}
}
Note: this code assumes you are using SQL Server, for other systems the format of the parameters in the connection string might change, e.g. for Oracle it should be :id instead of #id.
I want to get a specific value out of my Database.
To do so I wrote a function that I call like that:
strUserId = SqlSelectToString("SELECT UserId FROM BugNet.dbo.Users WHERE UserName = #UserName");
The function works like that:
private string SqlSelectToString(string strSqlCommand)
{
string result = "";
using (SqlConnection connection = new SqlConnection(strConnectionString))
{
using (SqlCommand command = new SqlCommand(strSqlCommand, connection))
{
command.Parameters.AddWithValue("#UserName", strUserName);
try
{
connection.Open();
result = (string)command.ExecuteScalar();
}
catch
{
if (connection.State == ConnectionState.Open)
{
connection.Close();
}
}
}
}
return result;
I tried many different approaches but wasn't able to add "strUserName" to the query.
The query-string remained always "SELECT UserId FROM BugNet.dbo.Users WHERE UserName = #UserName".
What am I doing wrong?
Thanks in advance.
EDIT:
The Username of whom we need the UserId is always the same and defined by the Webserver-Admin through the Web.config as follows:
<appSettings>
<add key="UserName" value="kunde"/>
<add key="ApplicationName" value="InternalTest"/>
before the method SqlSelectToString is executed I fetch the strUsername from the config like that:
strUserName = System.Configuration.ConfigurationManager.AppSettings["UserName"].ToString();
Hope that helps.
EDIT:
Finally found a solution to the problem.
This is the right approach:
private const string strSelectUserId = "SELECT UserId FROM BugNet.dbo.Users WHERE UserName = #UserName";
/// <summary>
/// Saves the result of an SQL-Query in a string
/// </summary>
/// <param name="strSqlCommand"></param>
private string SqlSelectToString(string strSqlCommand)
{
string result = "";
SqlConnection connection = new SqlConnection(strConnectionString);
SqlCommand command = new SqlCommand(strSqlCommand, connection);
command.Parameters.AddWithValue("#UserName", strUserName);
command.Parameters.AddWithValue("#ApplicationName", strApplicationName);
command.Parameters.AddWithValue("#ProjectId", strProjectId);
SqlDataReader reader;
try
{
connection.Open();
reader = command.ExecuteReader();
while (reader.Read())
{
result = reader[0].ToString();
}
}
catch
{
bInsert = false;
}
finally
{
if (connection != null)
{
connection.Close();
connection.Dispose();
}
}
return result;
}
The query-string remained always "SELECT UserId FROM BugNet.dbo.Users WHERE UserName = #UserName".
This is what is supposed to happen. It's the whole point of parameterized queries. The parameter value is never substituted directly into the sql command, and thus any possibility of an sql injection attack is avoided. Instead, it's more as if you executed sql code like this:
declare #UserName nvarchar(50);
set #UserName = '... magic here to populate this without actually building sql code';
SELECT UserId FROM BugNet.dbo.Users WHERE UserName = #UserName
(Though for Sql Server it actually relies on sp_executesql)
I'd help you more, but you never tell us what actually happens after you run the code... and this is likely because you swallow any exception that might tell you what went wrong. The code you have is almost certainly throwing an exception that would tell you exactly what's going wrong here, and you never get to see it.
Seriously, just remove the try/catch from that code entirely. You don't need it at all, and the entire catch block is just extra code.
One more thing before I go: AddWithValue() isn't the best option for your query parameters.
Put all that together, you end up with a helper method that looks more like this:
private string GetSqlScalar(string strSqlCommand, params SqlParameter[] parameters)
{
string result = "";
using (SqlConnection connection = new SqlConnection(strConnectionString))
using (SqlCommand command = new SqlCommand(strSqlCommand, connection))
{
if (parameters != null)
{
command.Parameters.AddRange(parameters);
}
connection.Open();
result = (string)command.ExecuteScalar();
}
return result;
}
And then call it like this:
strUserId = GetSqlScalar("SELECT UserId FROM BugNet.dbo.Users WHERE UserName = #UserName",
new SqlParameter("#UserName", SqlDbType.NVarChar, 50) {Value = strUserNanme });
(Of course using the correct parameter type and length from the database).
I ran into another issue again. I was trying to get data from the database using DataReader but I got the error when i was testing my code. Can anyone help me out? The error occurred at this line:
chkAssess = readAssess[columnName].ToString();
Below is the code snippet:
public string CheckAssess(string emailAddress, string columnName)
{
string chkAssess = "";
SqlDataReader readAssess;
//readAssess = new SqlDataReader();
string MgrAssessQry = "SELECT '"+columnName+"' FROM tblAllUsers";
//MgrAssessQry += " WHERE email ='" + emailAddress + "'";
SqlCommand cmdReadAssess = new SqlCommand(MgrAssessQry, cn);
cn.Open();
readAssess = cmdReadAssess.ExecuteReader();
while(readAssess.Read())
{
// Add the rows
chkAssess = readAssess[columnName].ToString();
}
return chkAssess;
}
try to use column name without ''
select something from table
instead of
select 'something' from table
for security reasons, don't create sql queries in that way (by concatenating strings) - use #parameters instead
2. close the reader at the end
Try this:
public string CheckAssess(string emailAddress, string columnName)
{
string chkAssess = "";
SqlDataReader readAssess;
//readAssess = new SqlDataReader();
string MgrAssessQry = "SELECT #Column_Name FROM tblAllUsers";
SqlCommand cmdReadAssess = new SqlCommand(MgrAssessQry, cn);
cmdReadAssess.Parameters.AddWithValue(new SqlParameter("Column_Name", columnName));
cn.Open();
readAssess = cmdReadAssess.ExecuteReader();
while(readAssess.Read())
{
// Add the rows
chkAssess = readAssess.GetString(0);
}
return chkAssess;
}
You have got several problems here.
Check whether your readAssess has rows like below.
if(readAssess.HasRows)
If it doesn't have rows then trying
chkAssess = readAssess.GetString(0);
would throw this error, as Arrays are index-based.
So your code should be like below
if(readAssess.HasRows)
{
while(readAssess.Read())
{
chkAssess = readAssess.GetString(0);
}
}
Other problem is you need to close both the reader & the connection afterwards.
readAssess.Close();
cn.Close();
Also your code is potentially vulnerable to SQL Injection.
if (reader.HasRows)
{
while (reader.Read())
{
int result = Convert.ToInt32(reader.GetString(0));
Console.WriteLine(result);
}
}
The most important thing is check the query first by executing in SQL Server and see if any result is coming or not.
Secondly based on the type of output you are receiving cast it to that particular data type (important).Mostly everyone is saving the data in varchar so.
I'm developing a C# solution with data access to Oracle.
And would like to have a generic solution about query.
Here is a part of my code :
public DataTable GetData(string query)
{
DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.OracleClient");
using (DbConnection conn = factory.CreateConnection())
{
try
{
DbConnectionStringBuilder csb = factory.CreateConnectionStringBuilder();
csb["Data Source"] = #"Northwind";
csb["User Id"] = #"Northwind";
csb["Password"] = #"Northwind";
conn.ConnectionString = csb.ConnectionString;
conn.Open();
using (DbCommand cmd = conn.CreateCommand())
{
cmd.CommandText = query;
using (DataTable dt = new DataTable())
{
DbDataAdapter da = factory.CreateDataAdapter();
cmd.CommandType = CommandType.Text;
da.SelectCommand = cmd;
da.Fill(dt);
return dt;
}
}
}
catch (Exception ex)
{
throw new Exception("Error", ex);
}
finally
{
if (conn.State != ConnectionState.Closed)
conn.Close();
}
}
}
And I call my method like this :
DataAccess.Provider data = new DataAccess.Provider();
DataTabel dt = dt.GetData("select * from myTable);
This works pretty good but this is not my aim.
I have a second class called CL_mpg with all my SQL queries.
class CL_MPG
{
public string rq_sql;
public string selectParam(string param)
{
this.rq_sql = "select * from myTable where id = '" + param + "';";
return this.rq_sql;
}
public string select()
{
this.rq_sql = "select * from myTable";
return this.rq_sql;
}
//...
}
And I would like to use my methods selectParam and/or select to fill my datatable, but I don't know how to do that.
Although others complain at your learning attempt, everyone has to start somewhere. Your method is actually an ok start, but I would change the parameter from a string to a DbCommand object. Then, you can create your methods to properly build the command and set proper parameters. Then pass the entire prepared command to your wrapper method (that creates connection, tests open successful, queries data, etc) and have your method return a DataTable object as you have... something like
public class CL_MPG
{
private DataTable GetData(DbCommand cmd )
{
// do all the same as you have with exception of your USING DBCOMMAND.
// just set the connection property of the incoming command to that of
// your connection created
// AT THIS PART --
// using (DbCommand cmd = conn.CreateCommand())
// {
// cmd.CommandText = query;
// just change to below and remove the closing curly bracket for using dbcommand
cmd.Connection = conn;
}
// Now, your generic methods that you want to expose for querying
// something like
public DataTable GetAllData()
{
DbCommand cmd = new DbCommand( "select * from YourTable" );
return GetData( cmd );
}
public DataTable GetUser( int someIDParameter )
{
DbCommand cmd = new DbCommand( "select * from YourTable where ID = #parmID" );
cmd.Parameters.Add( "#parmID", someIDParameter );
return GetData( cmd );
}
public DataTable FindByLastName( string someIDParameter )
{
DbCommand cmd = new DbCommand( "select * from YourTable where LastName like #parmTest" );
cmd.Parameters.Add( "#parmTest", someIDParameter );
return GetData( cmd );
}
}
Notice the command is being built and fully prepared and parameterized vs concatination of strings as prior comment was made which could expose you to SQL-injection. As for the parameters, and not querying Oracle, they may need to be tweaked some. Different engines use slightly different conventions. If connecting to SQL-Server database, it uses "#" to identify a parameter. In SyBase Advantage Database, it uses ":". Using Visual FoxPro, a simple "?" placeholder is used.
Also, if your query has many criteria, just keep adding additional "#parm" type placeholders, then add your parameters in the same order as they appear in your query just to make sure you didn't miss any. Some functions could have none, one or more based on your needs. Then, in the samples provided, its as simple as doing something like
DataTable whoIs = yourCL_MPGObject.GetUser( 23 );
if( whoIs.Rows.Count > 0 )
MessageBox.Show( whoIs.Rows[0]["WhateverColumnName"] );
I'm new to Visual Studio 2010 and I'm trying to create a Login form.
I have this code.
OdbcConnection con = new OdbcConnection("host=localhost;usr=root;password=admin;db=timekeeping;");
OdbcCommand cmd = new OdbcCommand("SELECT * FROM receptionist WHERE username = '" + username_login.ToString() + "' AND password = '" + password_login.ToString() + "';");
cmd.Connection = con;
con.Open();
OdbcDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
if (reader.GetString(0) != 1)
{ return false; }
else
{ return true; }
}
cmd.Connection.Close();
reader.Dispose();
cmd.Dispose();
There are errors but I don't know what is the problem with that.
Here's a screenshot:
Hoping that someone ca help me..
Thanks
Your code is vulnerable to SQL Injection. Never use string concatenations when building your SQL queries. Use parametrized queries instead:
public bool IsValid(string username, string password)
{
using (var conn = new OdbcConnection("host=localhost;usr=root;password=admin;db=timekeeping;"))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "SELECT count(*) FROM receptionist WHERE username = #username AND password = #password;";
cmd.Parameters.AddWithValue("#username", username);
cmd.Parameters.AddWithValue("#password", password);
var count = (long)cmd.ExecuteScalar();
return count > 0;
}
}
and then call like this:
bool isValid = IsValid(username_login.ToString(), password_login.ToString());
Also if you are using SQL Server you are better with SqlConenction instead of ODBC driver.
You can't compare a string to an int which you are trying here:
if (reader.GetString(0) != 1)
You could use GetInt32:
http://msdn.microsoft.com/en-us/library/system.data.odbc.odbcdatareader.getint32.aspx
And you shouldn't build your SQL like this but use parameters instead of just constructing a string. You're vulnerable to SQL injection with this way of constructing your SQL code.
Well the error message is pretty OdbcDataReader.GetString returns a string not an int. Therefore you can't compare it. See MSDN
You probably want to check the length of it? if (reader.GetString(0).Length != 1)
Replace in your code this line
if (reader.GetString(0) != 1)
with this
if (int.Parse(reader.GetString(0)) != 1)
Second,
In your userLogin() method you are tryin to return a value whereas the reeturn type is void. Change the return type.
if (reader.GetString(0) != "1")
{ return false; }
else
{ return true; }
Trying to compare an int and a string won't really work.
you can also do
if (Convert.ToInt32(reader.GetString(0)) != 1)
{ return false; }
else
{ return true; }
However, in some cases this might not work.
And in addition, I'd rather use GetSqlString and convert it instead of using GetString because I had too many problems with nulls when I was coding.