How to efficiently update a huge amount of data via code - c#

I am working on updating a huge amount of data. About 200k of data in the particular table. But I find my code inefficient and slow. Is there a way to optimize this code and make it twice or thrice faster? I am trying to convert their existing password to hashed. I tried linq before but I encounter an "Execution Timeout" issue. Until now I can't find a solution to it. The code below was the one that I am currently using.
var hashedProvider = Membership.Providers["HashedProvider"];
if (hashedProvider != null)
{
using (SqlConnection con = new SqlConnection(System.Configuration
.ConfigurationManager.ConnectionStrings["Connection"].ConnectionString))
{
con.Open();
string sql = "SELECT Email from aspnet_membership where IsLockedOut = '0'" +
" AND IsApproved = '1' And PasswordFormat != '1'";
SqlCommand cmd = new SqlCommand(sql, con);
SqlDataReader Reader = cmd.ExecuteReader();
while (Reader.Read())
{
var UserName = Reader["Email"].ToString();
MembershipUser user = Membership.GetUser(UserName);
if (user != null)
{
Guid userID = new Guid(user.ProviderUserKey.ToString());
string CurrentPassword = user.GetPassword();
try
{
UpdateUser(userID, 1);
var resetPassword = hashedProvider.ResetPassword(UserName, null);
bool Password_Changed = hashedProvider.ChangePassword(
UserName, resetPassword, CurrentPassword);
if (!Password_Changed)
{
UpdateUser(userID, 2);
}
}
catch (Exception e)
{
UpdateUser(userID, 2);
}
}
}
if (Reader != null)
Reader.Close();
}
}
Below is the code for UpdateUser() method.
public static void UpdateUser(Guid userID, int type)
{
for (Int32 attempt = 1; ;)
{
using (SqlConnection con = new SqlConnection(System.Configuration
.ConfigurationManager.ConnectionStrings["Connection"].ConnectionString))
{
con.Open();
string Sql = "UPDATE [aspnet_Membership] SET [PasswordFormat] = #Type where" +
" UserID = #UserID";
SqlCommand cmd = new SqlCommand(Sql, con);
cmd.Parameters.AddWithValue("#UserID", userID);
cmd.Parameters.AddWithValue("#Type", type);
cmd.ExecuteNonQuery();
break;
}
}
}

Related

SQL commands not working in C# (ASP.NET web forms)

I'm having a trouble with my code.
I'm trying to have the user the ability to submit his email to subscribe to my "notify me" service, I havn't code anything lately so I a bit confused..
I'm trying to Insert, Read, and Update data in my Online SQL Server.. but nothing seems to work! I don't know why I tried everything I know I check a million times it seems good.
Plus if there is any errors my catch should show it to me but even that doesn't work :(
Take a look at this maybe your eyes will see something I don't see.
protected void btnSubmit_Click(object sender, EventArgs e)
{
string cs = ConfigurationManager.ConnectionStrings["notifyCS"].ConnectionString;
using (SqlConnection conn = new SqlConnection(cs))
{
conn.Open();
try
{
string checkEmail = "SELECT User_Email FROM tbl_users WHERE User_Email = #User_Email";
string checkSubscription = "SELECT User_Status FROM tbl_users WHERE User_Email = #User_Email";
string submitEmail = "INSERT INTO tbl_users (User_UID, User_Email, User_Status) VALUES (#User_UID, #User_Email, #User_Status)";
string submitEmail2 = "UPDATE tbl_users SET User_UID = #User_UID, User_Status = #User_Status WHERE User_Email = #User_Email";
SqlCommand emailCMD = new SqlCommand(checkEmail, conn);
SqlDataAdapter emailSDA = new SqlDataAdapter
{
SelectCommand = emailCMD
};
DataSet emailDS = new DataSet();
emailSDA.Fill(emailDS);
//if there is no email registered.
if (emailDS.Tables[0].Rows.Count == 0)
{
SqlCommand registerEmail = new SqlCommand(submitEmail, conn);
string User_UID = System.Guid.NewGuid().ToString().Replace("-", "").ToUpper();
registerEmail.Parameters.AddWithValue("#User_UID", HttpUtility.HtmlEncode(User_UID));
registerEmail.Parameters.AddWithValue("#User_Email", HttpUtility.HtmlEncode(email.Text));
registerEmail.Parameters.AddWithValue("#User_Status", HttpUtility.HtmlEncode("subscribed"));
registerEmail.ExecuteNonQuery();
registerEmail.Dispose();
conn.Close();
conn.Dispose();
email.Text = null;
}
else if (emailDS.Tables[0].Rows.Count > 0)
{
using (SqlCommand checkSub = new SqlCommand(checkSubscription, conn))
{
checkSub.Parameters.AddWithValue("#User_Email", HttpUtility.HtmlEncode(email.Text));
SqlDataReader sdr = checkSub.ExecuteReader();
if (sdr.HasRows)
{
string res = sdr["User_Status"].ToString();
if (res != "subscribed")
{
using (SqlCommand registerEmail2 = new SqlCommand(submitEmail2, conn))
{
string User_UID = System.Guid.NewGuid().ToString().Replace("-", "").ToUpper();
registerEmail2.Parameters.AddWithValue("#User_UID", HttpUtility.HtmlEncode(User_UID));
registerEmail2.Parameters.AddWithValue("#User_Email", HttpUtility.HtmlEncode(email.Text));
registerEmail2.Parameters.AddWithValue("#User_Status", HttpUtility.HtmlEncode("subscribed"));
registerEmail2.ExecuteNonQuery();
registerEmail2.Dispose();
conn.Close();
conn.Dispose();
email.Text = null;
}
}
else
{
conn.Close();
conn.Dispose();
Response.Redirect("index.aspx");
}
}
}
}
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
finally
{
conn.Close();
if (conn.State != ConnectionState.Closed)
{
conn.Close();
conn.Dispose();
}
}
}
}
Try it this way:
using (SqlConnection conn = new SqlConnection(cs))
{
conn.Open();
string checkEmail = "SELECT * FROM tbl_users WHERE User_Email = #User";
SqlCommand emailCMD = new SqlCommand(checkEmail, conn);
emailCMD.Parameters.Add("#User", SqlDbType.NVarChar).Value = email.Text;
SqlDataAdapter da = new SqlDataAdapter(emailCMD);
SqlCommandBuilder daU = new SqlCommandBuilder(da);
DataTable emailRecs = new DataTable();
emailRecs.Load(emailCMD.ExecuteReader());
DataRow OneRec;
if (emailRecs.Rows.Count == 0)
{
OneRec = emailRecs.NewRow();
emailRecs.Rows.Add(OneRec);
}
else
{
// record exists
OneRec = emailRecs.Rows[0];
}
// modify reocrd
OneRec["User_UID"] = User_UID;
OneRec["User_Email"] = email.Text;
OneRec["User_Status"] = "subscribed";
email.Text = null;
da.Update(emailRecs);
}
}

.Rows.Count always returns -1 even if record in database already exists?

Basically I want to check, using c#, if there is a username in the database already existing. If there is not-it must be created.
Below is the code that is doing exactly that(only the checking part matters in my opinion, but I have added the code for the adding part anyways)
Problem is that no matter what-if it exists or not, it always returns -1
public Boolean checkUser()
{
var connection = new MySqlConnection("Server=127.0.0.1;Database=book_library;user=root;password=root2");
var table = new DataTable();
connection.Open();
string checkUsernameQuery = "SELECT * FROM accounts WHERE username = 'usernameInputField.Text'";
var adapter = new MySqlDataAdapter();
MySqlCommand command = new MySqlCommand(checkUsernameQuery, connection);
//command.Parameters.Add("#username", MySqlDbType.VarChar).Value = usernameInputField.Text;
adapter.SelectCommand = command;
adapter.Fill(table);
if (table.Rows.Count > 0)
{
return true;
}
else
{
return false;
}
}
Here is the adding part(just adding it, but it is not too related with the problem)
private void registerIconButton_Click(object sender, EventArgs e)
{
checkUser();
var connection = new MySqlConnection("Server=127.0.0.1;Database=book_library;user=root;password=root2");
connection.Open();
string insertQuery = "INSERT INTO `accounts` (username, password, email) VALUES ('" + usernameInputField.Text + "','" + passwordInputField.Text + "','" + emailInputField.Text + "')";
MySqlCommand command = new MySqlCommand(insertQuery, connection);
command.Parameters.Add("#username", MySqlDbType.VarChar).Value = usernameInputField.Text;
command.Parameters.Add("#password", MySqlDbType.VarChar).Value = passwordInputField.Text;
command.Parameters.Add("#email", MySqlDbType.VarChar).Value = emailInputField.Text;
if (checkUser())
{
MessageBox.Show("This username already exists!");
}
else
{
if (command.ExecuteNonQuery() == 1)
{
}
else
{
MessageBox.Show("ERROR");
}
}
connection.Close();
}
Connections and Commands are disposable so you should put them inside using blocks to deterministically clean up resources.
If you just want to know if something exists, you can use ExecuteScalar instead of using a heavy-weight adapter.
Then just return the result of the expression != null to get your boolean that indicates if the user is there or not.
using(var connection = new MySqlConnection("Server=127.0.0.1;Database=book_library;user=root;password=root2"))
using(var cmd = connection.CreateCommand())
{
connection.Open();
string checkUsernameQuery = "SELECT TOP 1 username FROM accounts WHERE username = #p1";
cmd.Parameters.Add(new MySqlParameter("#p1", MySqlDbType.VarChar).Value = usernameInputField.Text;
var user = cmd.ExecuteScalar();
return user != null;
}

How to update a value after login

I want to set isLogged to 1 after login, login work but query doesn't work.
Query :
//
public static string loginUpdate = #"UPDATE users SET isLogged = #isLogged WHERE username = #username";
//
public bool userLogin(string userName, string password)
{
SqlConnection conn = db.initializare();
UserModel user = null;
int userId ;
int isLogged = 1;
try
{
cmd = new SqlCommand(Query.loginCheck, conn);
//cmd = new SqlCommand(Query.loginUpdate, conn);
cmd.Parameters.Add(new SqlParameter("username", userName));
cmd.Parameters.Add(new SqlParameter("password", password));
cmd.Parameters.AddWithValue("#isLogged", isLogged);
reader = cmd.ExecuteReader();
while (reader.Read())
{
userName = reader["username"].ToString();
password = reader["password"].ToString();
userId = Int32.Parse(reader["userID"].ToString());
user = new UserModel(userName, password,userId);
if (user != null)
{
cmd = new SqlCommand(Query.loginUpdate, conn);
return true;
}
}
}
catch (Exception ex)
{
var mesajEroare = ex.Message + "-" + ex.InnerException; ;
}
finally
{
conn.Dispose();
conn.Close();
}
return false;
}
You may need to write two separate SqlCommands to perform two operations:
For login check
For login update
Also, always make it a habit to use the using statement when dealing with an object that eats resources such as SqlConnection and SqlCommand. so objects will be automatically disposed after using them.
This will make your code cleaner without explicitly calling the Dispose() call.
Finally, I would suggest you place your SQL operation outside your Button Click event to avoid getting your code more complex. That way it's clean and easy to manage.
To summarize that, here's how your code is going to look like:
private string GetUserPassword(string userName){
using (SqlConnection connection = db.initializare()) {
string sqlQuery = "SELECT password FROM users WHERE username = #UserName";
using (SqlCommand cmd = new SqlCommand(sqlQuery, connection)) {
connection.Open();
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#UserName", userName);
var result = cmd.ExecuteScalar();
return (result == DBNull.Value) ? string.Empty : result;
}
}
}
private void UpdateLogin(string userName, int isLogged){
using (SqlConnection connection = db.initializare()) {
string sqlQuery = "UPDATE users SET isLogged = #isLogged WHERE username = #username";
using (SqlCommand cmd = new SqlCommand(sqlQuery, connection)) {
connection.Open();
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#UserName", userName);
cmd.Parameters.AddWithValue("#isLogged", isLogged);
cmd.ExecuteNonQuery();
}
}
}
public bool UserLogin(string userName, string password)
{
string userPassword = GetUserPassword(userName);
if (password.Equals(userPassword)){
UpdateLogin(userName,1);
return true;
}
else{
//username or password is incorrect
}
return false;
}

I want to check the username is already exists in my database table or not?

i have registration page and i want to check that username is already exist in database or not in 3 tier architecture.
MyRegistration.cs:
public static int checkusername(string user_txt)
{
int id2 = 0;
string selectstr = "select * from xyz where UserName = '" + user_txt + " ' ";
id2 = DataAccessLayer.ExecuteReader(selectstr);
return id2;
}
and the code behind onclick event of textbox:
protected void txt_username_TextChanged(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(txt_username.Text))
{
int id = xyz.checkusername(txt_username.Text.Trim());
if (id > 0)
{
lblStatus.Text = "UserName Already Taken";
}
else
{
lblStatus.Text = "UserName Available";
}
}
}
DataAccessLayer:
public static int ExecuteReader(string Query)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = GetConnectionString();
con.Open();
int id = 0;
SqlCommand cmd = new SqlCommand();
cmd.CommandText = Query;
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = con;
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
id++;
}
cmd = null;
reader.Close();
con.Close();
return id;
}
I have edited some of your codes try like below... it will help you...
Text change Event :
protected void txt_username_TextChanged(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(txt_username.Text))
{
if (xyz.checkusername(txt_username.Text.Trim()))
{
lblStatus.Text = "UserName Already Taken";
}
else
{
lblStatus.Text = "UserName Available";
}
}
}
Check Username :
public bool CheckUsername(string user_txt)
{
bool Result;
Result = DataAccessLayer.ExecuteReader(user_txt);
return Result;
}
Excute Reader :
public bool ExecuteReader(string user_txt)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = GetConnectionString();
con.Open();
SqlCommand cmd = new SqlCommand("select * from xyz where UserName = #UserID", con);
SqlParameter param = new SqlParameter();
param.ParameterName = "#UserID";
param.Value = user_txt;
cmd.Parameters.Add(param);
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
return true;
else
return false;
}
Usually if the "select query" doesn't find a userName with the parameter user_txt you'll id2 will be end up with the value -1. So the appropriate code would be:
if (id ==-1)
{
lblStatus.Text = "UserName Available";
}
if (id>0)
{
lblStatus.Text = "UserName Already Taken";
}
By the way, your code is highly insecure and your database can be easily attacked using SQL Injection I'd recommend you to understand this issue and add parameters to the query to prevent it. C# has its ways to implement this. Don't try to fix the access to the database, just start from scrath keeping in mind SQL Injection.
As others have mentioned, this approach has potentially serious security issues.
However, your problem may lie here user_txt + " ' ". The spaces around the second ', specifically the one before it may lead to the usernames not matching as expected.

Getting trouble in Login Page 3-Tire architecture

Bussiness Access Layer :
public static int login(string userlogin, string pwdlogin)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = GetConnectionString();
con.Open();
int id = 0;
string selectstr = "SELECT UserName, Password FROM Registration WHERE UserName = '" + userlogin.Trim() + "' AND Password = '" + pwdlogin.Trim() + "'";
SqlCommand cmd = new SqlCommand();
cmd.CommandText = selectstr;
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = con;
id = cmd.ExecuteNonQuery();
cmd = null;
con.Close();
return id;
}
Login.cs
protected void Button1_Click(object sender, EventArgs e)
{
int id = BusinessAccessLayer.login(userlogin.Text.Trim(), pwdlogin.Text.Trim());
if (id > 0)
{
message.Text = " valid";
}
else
{
message.Text = "in valid";
}
}
Okay, there are multiple things wrong here:
1) You should use using statements to make sure you close your connection and command even if exceptions are thrown
2) You should use parameterized SQL instead of putting the values directly into your SQL statement, to avoid SQL Injection Attacks
3) You appear to be storing passwords in plain text. Don't do that. Use a salted hash or something similar (ideally something slow to compute).
4) You're ignoring .NET naming conventions; methods should be in PascalCase
5) Your SQL never looks at any field which appears to be related to the user ID. It's not clear what you expect ExecuteNonQuery to return, but if you want the actual ID, you'll need to refer to it in the SQL. (Even if initially you just want to know whether or not the user's password is valid, I strongly suspect that at some point you'll want to user the real user ID, so you should make your code return it. If you really only want to know whether or not the password is valid, you should change the method's return type to bool.)
6) You're using ExecuteNonQuery when your command clearly is a query. Either use ExecuteReader or ExecuteScalar instead. (ExecuteNonQuery is meant for insert, delete and update statements, and it returns you the number of rows affected by the command.)
So something like:
public static int Login(string user, string password)
{
using (var conn = new SqlConnection(GetConnectionString()))
{
conn.Open();
string sql = "select Id, PasswordHash from logins where Username=#Username";
using (var command = new SqlCommand(sql))
{
command.Parameters.Add("#Username", SqlDbType.NVarChar).Value = user;
using (var reader = command.ExecuteRead())
{
if (reader.Read())
{
int id = reader.GetInt32(0);
string hash = reader.GetString(1);
// TODO: Hash provided password with the same salt and compare
// results
if (CheckPassword(password, hash))
{
return id;
}
}
return 0; // Or use an int? return type and return null
}
}
}
}
The ExecuteNonQuery is used for For UPDATE, INSERT, and DELETE statements.
For SELECT statements, use ExecuteReader
public static int login(string userlogin, string pwdlogin)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = GetConnectionString();
con.Open();
int id = 0;
string selectstr = "SELECT UserName, Password FROM Registration WHERE UserName = '" + userlogin.Trim() + "' AND Password = '" + pwdlogin.Trim() + "'";
SqlCommand cmd = new SqlCommand();
cmd.CommandText = selectstr;
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = con;
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
id++;
}
cmd = null;
reader.Close();
con.Close();
return id;
}
You can't use .ExecuteNonQuery if you want a result. Use .ExecuteReader.
public static int login(string userlogin, string pwdlogin)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = GetConnectionString();
con.Open();
int id = 0;
string selectstr = "SELECT UserId FROM Registration WHERE UserName = '" + userlogin.Trim() + "' AND Password = '" + pwdlogin.Trim() + "'";
SqlCommand cmd = new SqlCommand();
cmd.CommandText = selectstr;
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = con;
SqlDataReader reader = cmd.ExecuteReader();
reader.Read();
id = reader.GetInt32("UserId");
reader.Close();
con.Close();
return id;
}

Categories

Resources