C# Generating new id from database on windows forms application - c#

I have to make automatic generate new AccountID on my load windows form app.
So for example when users start windows form "Add new Account" in textbox for "Account id" I have to show latest value from database. If i have two accounts in database on windows form in textbox value will be three.
My code perfectly work if i have at least one account in database, but when my database is empty i got exception.
This is my code:
public int GetLatestAccountID()
{
try
{
command.CommandText = "select Max(AccountID)as maxID from Account";
command.CommandType = CommandType.Text;
connection.Open();
OleDbDataReader reader= command.ExecuteReader();
if (reader.Read())
{
int valueID = Convert.ToInt32(reader["maxID"]);
return valueID + 1;
}
return 1;
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (connection!= null)
{
connection.Close();
}
}
}
Also I find answer on stackoverflow:
object aa = DBNull.Value;
int valueID = (aa as int?).GetValueOrDefault();
But this line of code works if my database is empty, but when I have one account in the database, it will always show on my windows form in account id textbox value one. I use Microsoft Access 2007 database.
I appreciate any help.

You may further simplify it like below,
Select isnull(max(accountID),0) as maxID from Account

I'm guessing you want:
public int GetLatestAccountID(string connectionString)
{
using(var dbConn = new OleDbConnection(connectionString))
{
dbConn.Open();
string query = "select Max(AccountID) from Account";
using(var dbCommand = new OleDbCommand(query, dbConn))
{
var value = dbCommand.ExecuteScalar();
if ((value != null) && (value != DBNull.Value))
return Convert.ToInt32(value) + 1;
return 1;
}
}
}
It looks like you're opening your database connection once and leaving it open during your entire program. Don't do that; that leads to race conditions and data corruption. .NET implements database connection pooling so you're not improving performance at all by leaving connections open.
You're also not telling us what you're using GetLatestAccountID for. If you're trying to use that as a primary key you are also going to run into problems with race conditions. If you want a primary key you should let the database create it and return the value after you've created the record.

public int GetLatestAccountID()
{
try
{
int accounts = 0;
command.CommandText = "select Max(AccountID)as maxID from Account";
command.CommandType = CommandType.Text;
connection.Open();
OleDbDataReader reader= command.ExecuteReader();
if (reader.Read())
{
accounts = Convert.ToInt32(reader["maxID"]) + 1;
}
return accounts;
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (connection!= null)
{
connection.Close();
}
}
}

Could you use SELECT COUNT(column_name) FROM table_name; to count number of accounts instead of selecting which one is the biggest?

Related

How to access the first column in SQL and why does this code give me error?

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.

SQL Ntext Items Only Having the First Two Chars Read in

I am currently programming a C# program that lets students log into an interface, check grades, etc.. Admins can create new users. The student IDs are 9-digit codes that all begin with "95." When an admin is creating a new user, I want to go through the database to make sure that the ID number they have entered isn't already taken.
To do this, I have the following code:
connection.Open();
readerUsers = commandUsers.ExecuteReader();
while (readerUsers.Read())
{
MessageBox.Show(readerUsers[2].ToString());
if(readerUsers[2].ToString() == IDNum)
{
userAlreadyExists = true;
break;
}
}
connection.Close();
And in my Users table, which readerUsers and commandUsers are connected to, I have the following:
IDuser Username 95Number Password Active Admin
-------------------------------------------------------------
1 sward 951619984 uo99lb True True
... ... ... ... ... ...
Now, when I went to test my code by creating a user with the ID number of 951619984 (a number already entered in the database), userAlreadyExists would still remain false. So I made the program show a message box of each item in the 95Number column (which is of type Ntext). Every time, the message box would only show "95".
I am very new to programming with databases, so I apologize if this is a very newby question, but I'm not sure what to do to get the whole string from this ntext column. Could someone explain what I'm doing wrong? Thank you for your time.
Here is a better way of doing that:
var connstr = ConfigurationManager.ConnectionStrings["your key"].ConnectionString;
var sql = "SELECT COUNT(*) FROM Users WHERE [95number]=#num";
using (var conn = new SqlConnection(connstr))
using (var cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.Add("num",SqlDbType.Int).Value = IDNum;
conn.Open();
var result = cmd.ExecuteScalar();
userAlreadyExists = result > 0;
}
I did mines this way.
string Qstring = "Select 95number where 95number = '95#########'";
using (SqlConnection Con = new SqlConnection(Form1.ConnectionStringGen))
using (SqlCommand Com = con.CreateCommand())
{
Com.CommandText = Qstring;
con.Open();
using (SqlDataReader Reader = Com.ExecuteReader())
{
if(Reader.Read())
{
string 95Numb = Reader["95Number"].ToString();
Messagebox.show(95Numb);
userAlreadyExists = true;
//meaning if the reader reads an item it will prompt
}
else
{
userAlreadyExists = false;
}
}
con.Close();
}
}
catch (Exception)
{
throw;
}

make many mysql command in one connection in c# visual studio & unknown column in where clause

I have mySql database contains ID, projectName, companyName, projectNum, .. etc
I need to create Combobox that display projectName (project name isn't unique)
when I try to execute this the following error appears:
"Unknown column 'proj2' in where clause"
even though when I try to print this value it prints successfully in my code.
so I changed to display ID in Combobox and works well
now I need if I choose one ID to fill some fields (projectName, companyName, projectNum) then display values in other Combobox (e.g Combobox2) it has item number which is not unique and it
depend on projectName field.
I try to make one connection and two connection but both of them didn't work.
nothing appears in Combobox2
when I try to choose ID from first Combobox the same error appears:
"Unknown column 'proj2' in where clause"
I don't know if should I change the design of the database.
again I should mention that project name, company name, project number may be repeated in more than 50 records.
below is the code
first function to fill the first Combobox:
private void Form2_Load(object sender, EventArgs e)
{
try
{
// String getQuery = "Select projectName From ubc.BOQ_Table Group By projectName";
String getQuery = "Select ID From ubc.BOQ_Table";
connection.Open();
MySqlCommand command = new MySqlCommand(getQuery, connection);
MySqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
comboBox1.Items.Add(reader.GetString("ID"));
}
}
reader.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
connection.Close();
}
second function to fill fields depend on choosing ID:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
//get vaalue of selected project
selectedProject = comboBox1.SelectedItem.ToString();
String selectQuery = "Select * From ubc.BOQ_Table where ID=" + selectedProject;
connection.Open();
MySqlCommand command = new MySqlCommand(selectQuery, connection);
MySqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
projectNameText.Text = reader.GetString("projectName");
projectName = projectNameText.Text;
companyNameText.Text = reader.GetString("companyName");
projectNumber.Text = reader.GetInt32("projectNumber").ToString();
reader.Close();
}
command.CommandText = "Select itemNum From ubc.BOQ_Table where projectName=" + projectName;
command.ExecuteNonQuery();
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
comboBox2.Items.Add(reader.GetString("itemNum"));
}
}
reader.Close();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
connection.Close();
}
This line of code is causing the problem:
command.CommandText = "Select itemNum From ubc.BOQ_Table where projectName=" + projectName;
As commenters have mentioned, concatenating strings is causing both the syntax error and makes your code vulnerable to SQL injection attacks. The solution is to use "parameterized queries" by putting the variable in a MySqlParameter object.
command.CommandText = "Select itemNum From ubc.BOQ_Table where projectName=#projectName;";
command.Parameters.AddWithValue("#projectName", projectName);
using (var reader = command.ExecuteReader())
{
// ...
(You may find some people saying "don't use AddWithValue", but that's an objection that applies just to SqlCommand; there's no good reason to avoid using it with MySqlCommand.)

Assigning SQL reader leaves code

I am having an issue with my c# code. I am trying to check if a username exists already so I have a select statement but when I breakpoint it, it leaves the code right after I assign the reader. Here is my code:
SqlConnection conn = new SqlConnection(Properties.Settings.Default.CategoriesConnectionString);
SqlCommand chkUser = new SqlCommand("SELECT [Username] FROM [Accounts] WHERE [Username] = #username", conn);
chkUser.Parameters.AddWithValue("#username", txtUsername.Text);
conn.Open();
SqlDataReader sqlReader = chkUser.ExecuteReader(); //leaves code right here
if (sqlReader.HasRows)
{
MessageBox.Show("That username already exists. Please choose another.");
txtUsername.Focus();
return;
}
conn.Close();
I figure it is because there is nothing in the table yet but I don't know why it is not checking whether or not it has rows and is just leaving.
Any help is appreciated. Thanks
Some more information on the issue would be useful. Seems like you are getting an exception for some reason (as #Guffa said) and without any further details it becomes difficult guessing what the reason is. Try changing the code you posted to the following:
using(SqlConnection conn = new SqlConnection(Properties.Settings.Default.CategoriesConnectionString))
using(SqlCommand chkUser = new SqlCommand("SELECT [Username] FROM [Accounts] WHERE [Username] = #username", conn))
{
chkUser.Parameters.AddWithValue("#username", txtUsername.Text);
try
{
conn.Open();
using(SqlDataReader sqlReader = chkUser.ExecuteReader())
{
if (sqlReader.HasRows)
{
MessageBox.Show("That username already exists. Please choose another.");
txtUsername.Focus();
return;
}
}
}
catch(Exception e)
{
// manage exception
}
}
and see if something changes. In case it doesn't try debugging and see what kind of exception it throws.
Here is an example that i use in a login scenario where i've stored usernames in a mysql database table.
Even though i use MySQL there shouldnt be much of a difference.(not sure about this though).
public static string CheckUsername()
{
bool usernameCheck = false;
InitiateDatabase();//contains the root.Connection string
MySqlCommand readCommand = rootConnection.CreateCommand();
readCommand.CommandText = String.Format("SELECT username FROM `SCHEMA`.`USERTABLE`");
rootConnection.Open();
MySqlDataReader Reader = readCommand.ExecuteReader();
while (Reader.Read())
{
for (int i = 0; i < Reader.FieldCount; i++)
{
if (Reader.GetValue(i).ToString() == USERNAME_STRING)
{
usernameCheck = true;
}
}
}
rootConnection.Close();
if (usernameCheck)
{
return "Succes";
}
else
{
return "Wrong Username!";
}
}
This is of course without exception handling, which you might find useful during testing and if its meant to be used by others.

Show messages according to the MySQL database data? C#

I want to get the values from MySQL database and that would need to show the messages according to values. But it does not happen and that will always show int privilege is 0. If I did not assign that default value, errors will be showing on the code.
How can I solve this issue and show messages according to the int privilege values?
private void button_login_Click(object sender, RoutedEventArgs e)
{
string username = usernameInput.Text;
string password = passwordInput.Password;
int privilege = 0;
try
{
//This is command class which will handle the query and connection object.
string Query = "SELECT`tbl_user_login`.`u_id`,`tbl_user_login`.`u_username`,
`tbl_user_login`.`u_password`,`tbl_user_login`.`u_privilege`
FROM `bcasdb`.`tbl_user_login`WHERE `tbl_user_login`.`u_username` = '"
+ username + "' AND `tbl_user_login`.`u_password` ='" + password
+ "' AND `tbl_user_login`.`u_privilege` = #privi;";
MySqlConnection conn =
new MySqlConnection(BCASApp.DataModel.DB_CON.connection);
MySqlCommand cmd = new MySqlCommand(Query, conn);
cmd.Parameters.AddWithValue("#privi", privilege);
MySqlDataReader MyReader;
conn.Open();
MyReader = cmd.ExecuteReader();
// Here our query will be executed and data saved into the database.
if (MyReader.HasRows && this.Frame != null)
{
while (MyReader.Read())
{
if (privilege == 1)
{
DisplayMsgBox("click ok to open the admin page ", "OK");
}
if (privilege == 2)
{
DisplayMsgBox("click ok to open the staff page ", "OK");
}
else
{
DisplayMsgBox("privilege 0", "ok");
}
}
}
else
{
DisplayMsgBox("sucess else", "ok");
}
conn.Close();
}
catch (Exception )
{
DisplayMsgBox("sucess catch", "ok");
}
}
Looks like what you're trying to do is checking the value of u_privilege column from tbl_user_login table instead of making a where condition based on privilege. You need to remove this where condition
AND `tbl_user_login`.`u_privilege` = #privi
and also remove the parameter assignment
cmd.Parameters.AddWithValue("#privi", privilege);
You can get the value of tbl_user_login.u_privilege by using MySqlDataReader.GetInt32 syntax inside while (MyReader.Read()) block
MyReader.GetInt32(3)
Please note that 3 is used because MyReader.GetInt32 requires a zero based index parameter and tbl_user_login.u_privilege is the fourth column from your query. The value should be assigned to privilege variable as below
privilege = MyReader.GetInt32(3)
On a side note, you should parameterize your query to avoid SQL injection. Here's the complete code after implementing the above changes
int privilege = 0;
try
{
//This is command class which will handle the query and connection object.
string Query = "SELECT`tbl_user_login`.`u_id`,`tbl_user_login`.`u_username`,
`tbl_user_login`.`u_password`,`tbl_user_login`.`u_privilege`
FROM `bcasdb`.`tbl_user_login`WHERE `tbl_user_login`.`u_username` =
#username AND `tbl_user_login`.`u_password` = #password;";
MySqlConnection conn =
new MySqlConnection(BCASApp.DataModel.DB_CON.connection);
MySqlCommand cmd = new MySqlCommand(Query, conn);
cmd.Parameters.AddWithValue("#username", username);
cmd.Parameters.AddWithValue("#password", password);
MySqlDataReader MyReader;
conn.Open();
MyReader = cmd.ExecuteReader();
// Here our query will be executed and data saved into the database.
if (MyReader.HasRows && this.Frame != null)
{
while (MyReader.Read())
{
privilege = MyReader.GetInt32(3)
if (privilege == 1)
{
DisplayMsgBox("click ok to open the admin page ", "OK");
}
if (privilege == 2)
{
DisplayMsgBox("click ok to open the staff page ", "OK");
}
else
{
DisplayMsgBox("privilege 0", "ok");
}
}
}
else
{
DisplayMsgBox("sucess else", "ok");
}
conn.Close();
}
catch (Exception )
{
DisplayMsgBox("sucess catch", "ok");
}
If im not wrong, the privilege is being returned as a string type. Try take it in as a string then cast it to an integer?

Categories