In PHP I am able to retrieve information from a db like so:
<?php
$sql = "SELECT * FROM users";
$result = mysql_query($sql);
$data = array();
while($row = mysql_fetch_assoc($result))
{
$data[] = $row;
}
I am trying to acomplish the same thing in C#:
OdbcCommand cmd = new OdbcCommand("SELECT * FROM users WHERE id = #id");
cmd.Parameters.Add("#id", id);
OdbcDataReader reader = cmd.ExecuteReader();
Dictionary<string, string> data = new Dictionary<string, string>();
while (reader.Read())
{
data.Add("id", reader.GetString(0));
data.Add("username", reader.GetString(1));
data.Add("firstName", reader.GetString(2));
}
return data;
Is it possible to reference the column in the table by name without going through all this trouble?
You can use the OdbcDataAdapter class to populate a DataSet, which would probably be a bit simpler.
Yes, but it is SLOW. Not slower than your approach, granted, but slow - I would mark your whole code for a review...
Dont ask for "*", ask for the fields. Good SQL practice - and as you know the fields, guess what, you dont ahve to guess them. On top, you assume id is fiel 0, username field 1...
If that is not possible - read the docomentation. There is a "GetOrdinal" method that takes a field name and.... returns.... the field index.
That said, this whole code is fully redundant. Have a look at proper data access layers, or at least BLTOOLKIT - you can move all that code into ONE abstract method with the rest being automatically generated.
Related
How can i prevent these code of getting SQL injected? It's a login system that i'm learning. Here's the code!
if (!(string.IsNullOrWhiteSpace(textBox1.Text)) && !(string.IsNullOrWhiteSpace(textBox2.Text)))
{
MySqlConnection mcon = new MySqlConnection("datasource = 127.0.0.1; port = 3306; username = root; password = ; database = rpgmaster;");
mcon.Open();
DataTable table = new DataTable();
MySqlDataAdapter adapter = new MySqlDataAdapter("Select * From users where Username = '" + textBox2.Text + "' and password = '" + textBox1.Text + "'", mcon);
adapter.Fill(table);
if (table.Rows.Count <= 0)
{
MessageBox.Show("Você não está registrado!");
}
else
{
MessageBox.Show("Logado com sucesso! ");
}
mcon.Close();
}
Thanks for the help! Really appreciate it!
If you're learning, you could perhaps move on from this old low level way of doing data access and use something a bit more modern and easy. Dapper is an example of a library that isn't a huge leap above what you already know but makes your life a lot nicer:
using(var conn = new MySqlConnection("conn str here"){
var sql = "SELECT count(*) FROM tblUsers WHERE username = #u AND password = #p";
var prm = new {
u = txtUsername.Text, //give your textboxes better names than textbox2,textbox1!
p = txtPassword.Text.GetHashCode() //do NOT store plain text passwords!
};
bool valid = await conn.QuerySingleAsync<int>(sql, prm) > 0;
if(valid)
... valid login code
else
... invalid login
}
Some notes on this:
dapper is a device that you simply give your sql and parameter values to
the sql holds #parameters names like #u
an anonymous typed object has properties called the same name as the parameter name, with a value, like u = "my username"
use async/await when running queries; dapper makes this easy. Avoid jamming your UI up on queries that take 10 seconds to run
in this case you only need to ask the db to count the matching records, you don't need to download them all to find out if there are any, so we use QuerySingleAsync<int> which queries a single value of type it, and if it's more than 0, the login was valid
never store password in a database in plaintext. Use a one way hashing function like MD5, SHA256 etc, even the lowly string.GetHashCode is better than storing plaintext, particularly because people use the same passwords all the time so anyone breaking into your db (very easy; the password is in the code) will reveal passwords treat people probably use in their banking etc. We can't really be asking, on the one hand, how to prevent a huge security hole like SQL injection, and then on the other hand leave a huge security hole like plaintext passwords ;)
always name your textboxes a better name than the default textboxX - it takes seconds and makes your code understandable. If Microsoft called all their class property names like that, then the entire framework would be full of things like myString.Int1 rather than myString.Length and it would be completely unusable
life is too short to spend it writing AddWithValue statements; use Dapper, Entity Framework, strongly typed datasets.. Some db management technology that eases the burden of writing that code
Where Dapper makes things really nice for you is its ability to turn objects into queries and vice versa; this above is just a basic count example, but suppose you had a User class:
class User
{
string Name { get; set; }
string HashedPassword { get; set; }
int age {get; set; }
}
And you had a table tblUsers that was similar (column names the same as the property names), then you could query like:
User u = new User() { Name = "someuser" };
User t = await conn.QuerySingleAsync<User>("SELECT Name, HashedPassword, Age FROM tblUsers WHERE Name = #Name", u);
We want to look up all the info of the someuser user, so we make a new User with that Name set (we could also use anonymous type, like the previous example) and nothing else, and we pass that as the parameters argument. Dapper will see the query contains #Name, pull the contents of the Name from the u user that we passed in, and run the query. When the results return it will create a User instance for us, fully populated with all the data from the query
To do this old way we'd have to:
have a command,
have a connection,
add parameters and values,
open the connection,
run the sql,
get a reader,
check if the reader had rows,
loop over the reader pulling the first row,
make a new User,
use reader.GetInt/GetString etc to pull the column values out one by one and
finally return the new user
oh and dispose of all the db stuff, close the connection etc
Writing that code is repetitive, and it is really boring. In computing, when we have something repetitive and boring, that we need to do thousands of times through out life (like serializing to json, calling a webservice, designing a windows UI) we find some way to make the computer do the repetitive boring bit; they do it faster and more accurately than we can. This is exactly what Dapper does; it does away with that boring repetitive and reduces it to a single line where you say what you want back, using what query, with what parameters. And it keeps your UI working:
await x.QueryAsync<type>(query, parameters)
Win. Seek out some Dapper tutorials! (I have no affiliation)
Try using parameters please see updated sample of your code below:
if (!(string.IsNullOrWhiteSpace(textBox1.Text)) && !(string.IsNullOrWhiteSpace(textBox2.Text)))
{
using (MySqlConnection mcon = new MySqlConnection("datasource = 127.0.0.1; port = 3306; username = root; password = ; database = rpgmaster;"))
{
mcon.Open();
MySqlCommand cmd = new MySqlCommand("Select * from users where username=?username and password=?password", mcon);
cmd.Parameters.Add(new MySqlParameter("username", textBox2.Text));
cmd.Parameters.Add(new MySqlParameter("password", textBox1.Text));
MySqlDataReader dr = cmd.ExecuteReader();
if (dr.HasRows == true)
{
MessageBox.Show("Você não está registrado!");
}
else
{
MessageBox.Show("Logado com sucesso! ");
}
}
}
Use parameters to pass and check their length, Use stored procedure instead of a query in the code. Use columns instead of * in Select. And please make sure you don't store the plain password in the DB
Use Parameters
using (MySqlConnection mcon = new MySqlConnection(connectionString))
{
string commandText = "SELECT * FROM users WHERE Username = '#tbxText'"
SqlCommand command = new SqlCommand(commandText, mcon);
command.Parameters.AddWithValue("#tbxText", textBox2.Text);
}
How to display the unitfunction value from mysql database and my query is below ,i don't know its right or wrong.
Help me out.
string fundev = "select unitfunctioncode from channels where channel_no = " + Channelid;
MySqlCommand getfun = new MySqlCommand(fundev, Connection1);
Console.WriteLine(getfun);
MAKE ENTITY CONTEXT FIRST:
YourEntity db= new YourEntity();
LINQ:
Console.Write(db.channels.Where(x=>x.channel_no == Channelid).Select(y=>y.unitfunctioncode));
This is modal first approach create modal from database and call this linq in controller
I'm not sure about the specifics of MySqlCommand, but I would expect to see an execute on your getfun object.
I would do something like this:
MySqlDataReader rdr = getfun.ExecuteReader();
while (rdr.Read())
{
Console.WriteLine(rdr[0]);
}
rdr.Close();
This takes into account multiple rows returned. You can omit the while loop if you're sure you will have a single row returned.
I try to read sql table and load all into a variable
Code:
String query2 = "";
query2 = String.Format("SELECT * FROM Seguridad.UsuarioPerfil WHERE UsuarioID = {0}", UsuarioID);
SQLService sqlservice2 = new SQLService();
DataTable reader2 = sqlservice.Leer(query2);
I want to store all data into a variable var tmpPerfiles as object.
I can do something like:
var tmpPerfiles ="";
foreach (DataRow row in reader.Rows)
{
tmpPerfiles = row["UsuarioId"].ToString();
tmpPerfiles = row["PerfilId"].ToString();
}
But I can´t call tmpPerfiles two times. How can I achieve that? Regards
Okay, first up: STOP! Do not EVER write SQL queries like this. SQL Injection Attack is still the #1 cause of security breaches and vulnerabilities (per OWASP), and it's exclusively caused by people writing SQL statements like this.
Never ever write SQL statements like:
statement = "SELECT something from sometable where " + someVar ...
... because all it takes is for that 'somevar' to have an apostrophe and some malicious hacking code, and you're granting an external entity access to your database. Don't even do it if you're not expecting the field to be user-provided or such - it's a bad habit, and it leads to horrendous security faults.
Instead, you should always use one of the following:
Stored Procedures with parameterized inputs. Aka, dbo.usp_FindUser,
which accepts #userName, and the proc has WHERE name = #userName
Parameterized Sql Command. Aka, creating a SqlCommand with "Select *
from something from someTable where userName = #userName", and then
adding a parameter to the SqlCommand of userName, and a value of what
user you're looking for.
Okay, all that said?
Keep in mind, a variable can contain a grouping of things. Generally, if you're looking to contain a table within a single variable? It'll typically look something like:
string x, int y, string z - fields within the Database
Class dataRecord - a class, which contains string x, int y, string z.
List<dataRecord> - a list of instances of a dataRecord class
... make sense? You've got one variable per column, which you group into a class. One instance of the class represents one data row. And then a List<> of that class represents multiple rows of that table (or just the whole table itself.)
Usually, code that follows SRP (but that doesn't use EntityFramework) will look something like:
List<myFancyClass> tableEntries = new List<myFancyClass>();
foreach (DataRow dr in myDataTable.Rows)
{
myFancyClass line = new myFancyClass(dr); // constructor that takes in a DataRow
tableEntries.Add(line);
}
... at that point, the table is stored in the tableEntries variable.
e.g.
use a dto for storing it into a list
private class TmpDto {
string UsuarioId { get; set;}
string PerfilId { get; set;}
}
var Ilist<TmpDto> list = new List<TmpDto>();
foreach (DataRow row in reader.Rows)
{
var dto = new TmpDto();
dto.UsuarioId = row["UsuarioId"].ToString();
dto.UsuarioId = row["PerfilId"].ToString();
list.Add(dto);
}
so you have several objects stored within a list
If you are using EntityFramework, this is really easy. After setting up a class for the object (containing all fields), just use linq to get the object.
var myData = UsuarioPerfil.Where(e => e.UsuarioID == UsuarioID).FirstorDefault();
If all you want to do is get values from a database and put them into something, then I think the introduction of a datatable is overkill. While the implementation is easy enough, it adds overhead. I'd opt to use a DbDataReader instead.
This is an example of extracting a single field, and then just adding it to a list.
List<string> results = new List<string>();
String query2 = "SELECT PerfilId FROM Seguridad.UsuarioPerfil WHERE UsuarioID = #USARIO";
SqlCommand cmd = new SqlCommand(query2, connection);
cmd.Parameters.Add(new SqlParameter("#USARIO", SqlDbType.VarChar));
cmd.Parameters[0].Value = UsuarioID;
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
results.Add(reader.GetString(0));
}
reader.Close();
You referenced two fields, but since UsuarioID was defined in the where clause, it didn't seem necessary to pull it back.
Also, as #DotNetDev mentioned, don't use literals... the use of parameters is not only SQL-Injection safe, but it's more scalable and actually friendlier to the database (compile-once, execute many).
Finally, if you want to pull back multiple fields, create a data (domain) object, and make your results a list of that object. If you need an example, feel free to ask.
The application I am developing is meant to be a quick and easy tool to import data to our main app. So the user loads in a CSV, meddles with the data a little and pushes it up to the database.
Before the data is pushed to the database, I have a verification check going on which basically says, "Does a customer exist in the database with the same name, account and sort codes? If so, put their guid (which is known already) into a list."
The problem is, the result variable is always 0; this is despite the fact that there is duplicate test data already in my database which should show a result. Added to that, using SQL Profiler, I can't see a query actually being executed against the database.
I'm sure that the ExecuteScalar() is what I should be doing, so my attention comes to the Parameters I'm adding to the SqlCommand... but I'll be blowed if I can figure it... any thoughts?
string connectionString = Generic.GetConnectionString("myDatabase");
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand check = new SqlCommand("select COUNT(*) from Customers C1 INNER JOIN CustomerBank B1 ON C1.Id = B1.CustomerId WHERE C1.Name = #Name AND B1.SortCode = #SortCode AND B1.AccountNumber = #AccountNumber", conn);
foreach (DataRow row in importedData.Rows)
{
check.Parameters.Clear();
check.Parameters.Add("#Name", SqlDbType.NVarChar).Value = row["Name"].ToString();
check.Parameters.Add("#SortCode", SqlDbType.NVarChar).Value = row["SortCode"].ToString();
check.Parameters.Add("#AccountNumber", SqlDbType.NVarChar).Value = row["AccountNumber"].ToString();
Object result = check.ExecuteScalar();
int count = (Int32)result;
if (count > 0)
{
DuplicateData.Add((Guid)row["BureauCustomerId"]);
}
}
}
Clarification: importedData is a DataTable of the user's data held in this C# application. During the ForEach loop, each row has various columns, a few of those being Name, SortCode and AccountNumber. The values seem to get set in the parameters (but will verify now).
I am making something that requires MySQL. I have the saving done from in-game, which is simply done by INSERT.
I have a column that will have a password in and I need to check if the inputted password matched any of the rows and then if it is, get all of the contents of the row then save it to variables.
Does anyone have an idea how to do this in C#?
//////////////////////////
I have found how to save and get the string, however it will only get 1 string at a time :(
MySql.Data.MySqlClient.MySqlCommand command = conn.CreateCommand();
command.CommandText = "SELECT * FROM (player) WHERE (pass)";
command.ExecuteNonQuery();
command.CommandType = System.Data.CommandType.Text;
MySql.Data.MySqlClient.MySqlDataReader reader = command.ExecuteReader();
reader.Read();
ayy = reader.GetString(1);
print (ayy);
if(ayy == password){
//something
}
My best practice is to use MySQLDataAdapter to fill a DataTable. You can then iterate through the rows and try to match the password.
Something like this;
DataTable dt = new DataTable();
using(MySQLDataAdapter adapter = new MySQLDataAdaper(query, connection))
{
adapter.Fill(dt);
}
foreach(DataRow row in dt.Rows)
{
//Supposing you stored your password in a stringfield in your database
if((row.Field<String>("columnName").Equals("password"))
{
//Do something with it
}
}
I hope this compiles since I typed this from my phone. You can find a nice explanation and example here.
However, if you are needing data from a specific user, why not specificly ask it from the database? Your query would be like;
SELECT * FROM usercolumn WHERE user_id = input_id AND pass = input_pass
Since I suppose every user is unique, you will now get the data from the specific user, meaning you should not have to check for passwords anymore.
For the SQL statement, you should be able to search your database as follows and get only the entry you need back from it.
"SELECT * FROM table_name WHERE column_name LIKE input_string"
If input_string contains any of the special characters for SQL string comparison (% and _, I believe) you'll just have to escape them which can be done quite simply with regex. As I said in the comments, it's been a while since I've done SQL, but there's plenty of resources online for perfecting that query.
This should then return the entire row, and if I'm thinking correctly you should be able to then put the entire row into an array of objects all at once, or simply read them string by string and convert to values as needed using one of the Convert methods, as found here: http://msdn.microsoft.com/en-us/library/system.convert(v=vs.110).aspx
Edit as per Prix's comment: Data entered into the MySQL table should not need conversion.
Example to get an integer:
string x = [...];
[...]
var y = Convert.ToInt32(x);
If you're able to get them into object arrays, that works as well.
object[] obj = [...];
[...]
var x0 = Convert.To[...](obj[0]);
var x1 = Convert.To[...](obj[1]);
Etcetera.