Checking and Saving/Loading from MySQL C# - c#

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.

Related

Getting Database values into variable form c#

I am developing a cricket simulation and i need to retrieve certain statistics from a players data. I've got the following code.
public List<float> BattingData()
{
con.ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString.ToString();
string query = "SELECT [INNS], [NOT OUTS], [AVG] FROM [" + batTeam + "] WHERE [Player] = '" + name + "';";
SqlCommand com = new SqlCommand(query, con);
con.Open();
using (SqlDataReader reader = com.ExecuteReader())
{
if(reader.HasRows)
{
while (reader.NextResult())
{
Innings = Convert.ToInt32(reader["INNS"]);
NotOuts = Convert.ToInt32(reader["NOT OUTS"]);
Avg = Convert.ToSingle(reader["AVG"]);
}
}
}
con.Close();
OutRatePG = (Innings = NotOuts) / Innings;
OutRatePB = OutRatePG / 240;
RunsPB = Avg / 240;
battingData.Add(OutRatePB);
battingData.Add(RunsPB);
return battingData;
}
The error that I am getting is that when I try to divie by 'Innings' it is saying cannot divide by zero, so I think the variables are being returned as zero and no data is being assigned to them.
This line is the issue:
while (reader.NextResult())
What this does is move the reader to the next resultset, ignoring the rest of the rows unread. To advance a reader to the next row, you need to call reader.Read() instead.
You have some other issues with your code:
You appear to have a separate table for each team. This is incorrect database design. You should create a Team table, with each team in it, and then foreign key your TeamResults table to it. Query it using INNER JOIN.
You are concatenating user-entered values to your query. This leaves you open to SQL injection attacks. Use parameters instead. (You cannot parameterize a table name, another reason you should do as above 1.)
You do not need to check for HasRows. If there are no rows, Read() will return false.
It looks like you only want one row. If that is the case you don't want a while(reader.Read()) loop, instead if(reader.Read()). (If you only need a single value, you can refactor the code to use command.ExecuteScalar().)
In database records check if value for Innings has 0
also you can try the below code before performing any operation.
> if(Innings>0) { OutRatePG = (Innings - NotOuts) / Innings; }

How to prevent SQL Injection in this code?

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);
}

Reading existing rows from a database using C#

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).

Update Query C# MySQL Forms

Before you comment please note that I understand that my code is vulnerable to SQL injection, please disregard any comments about it being vulnerable for purposes of simplicity
I've checked around the website for answers but none seem to fit my situation, many are PHP.
I am trying to update information on a MySQL database from C# Forms Application on Visual Studio 2012, so I've allowed the user to input data but I want them to be able to update their data.
I've tried all sorts of different methods many give me errors, I feel like I'm very close with this method.
string Connection = "server = xxxx; " + "database = xxxxx; " + "uid = xxxx;"+ "pwd = xxxxx;";
MySqlConnection Conn = new MySqlConnection(Connection);
try
{
MySqlDataAdapter dAdapter = new MySqlDataAdapter("SELECT * FROM example", Conn);
DataTable dTable = new DataTable();
dAdapter.Fill(dTable);
DataRow dr = dTable.NewRow();
dr["TestData1"] = Convert.ToInt32(cboTestData1.Text);
dr["TestData2"] = txtTestData2.Text;
dr["TestData3"] = Convert.ToInt32(txtTestData3.Text);
dTable.Rows.Add(dr);
string Query = "Update example(field 1, field 2, field 3) VALUES ("TestData1", "TestData2", "TestData3")";
dTable.Rows.Add(Query);
MySqlCommandBuilder commandBuilder = new MySqlCommandBuilder(dAdapter);
int iRowsAffected = dAdapter.Update(dTable);
if (iRowsAffected == 1)
{
MessageBox.Show("Record Added", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("Error adding record", "Record Added", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
catch (MySqlException ex)
{
MessageBox.Show(ex.Message);
}
The issue is that it doesn't like the 'Query' code due to it being bad. It gives me this error message
Additional information: Input string was not in a correct
format.Couldn't store in ID Column. Expected
type is Int32.
I've looked around the internet for solutions but all either do not offer the same situation as mine or are related to PHP code.
The update query should be in a syntax of...
update SomeTable
set SomeField = NewValue,
AnotherField = AnotherValue
where
SomeKey = KeyIDTheUserWasWorkingWith
Also, for future, I know this is sample mach-up data/columns, but you should really use real table / column names. The sample data, we know could be made up to prevent confidentiality, but real structures are more practical to get answers accurate.
The INSERT statement is closer to what you have and is ...
insert into SomeTable
( fld1, fld2, fld3 )
values
( someFld1, anotherFld2, lastField )
Finally, with your column names, if you DO (but I never do), have columns with embedded spaces, be sure to
`wrap in tic marks`
, so the engine recognizes the whole string as the column name.
I think there is some confusion in your code.
The SELECT statement may be bringing back 4 fields such as: ID, TestData1, TestData2, TestData3.
You then fill a DataTable with the records retrieved from the database.
Next, you create a new DataRow in the DataTable (that will have the four columns that match the SELECT statement). You place values into the editable fields (not the ID field).
Then you add the DataRow to the DataTable.
Here its where it gets mixed up...
You create a SQL Update Query String - then add that string as a DataRow to the DataTable.
When updating the DataTable via the MySqlDataAdapter, the last DataRow is not a valid record to be parsed by the Adapter.
Try removing the two lines:
string Query = "Update example(field 1, field 2, field 3) VALUES ("TestData1", "TestData2", "TestData3")";
dTable.Rows.Add(Query);

Getting column info from db with C#

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.

Categories

Resources