When creating User, I need to give it a system Role, so I was wondering what is the best way to do that.
I have working solution, but I'm unsure if it's the best way.
using (SqlConnection con = new SqlConnection(conString))
{
con.Open();
using (SqlCommand cmd = new SqlCommand(#"INSERT INTO Users (Name, Email, Username, Password, Active) VALUES (#Name, #Email, #Username, #Password, #Active); SELECT SCOPE_IDENTITY();", con))
{
try
{
cmd.Parameters.AddWithValue("#Name", user._Name);
cmd.Parameters.AddWithValue("#Email", user._Email);
cmd.Parameters.AddWithValue("#Username", user._Email);
cmd.Parameters.AddWithValue("#Password", user.Password);
cmd.Parameters.AddWithValue("#Active", 1);
user_id = Convert.ToInt32(cmd.ExecuteScalar());
//cmd.ExecuteNonQuery();
}
catch (SqlException)
{
//Handle Exception
}
}
}
using (SqlConnection con = new SqlConnection(conString))
{
using (SqlCommand cmd = new SqlCommand("INSERT INTO User_Role (User_Role_User_Id, User_Role_Role_Id) VALUES (#User_ID, #Role_ID)", con))
{
try
{
cmd.Parameters.AddWithValue("#User_ID", user_id);
cmd.Parameters.AddWithValue("#Role_ID", user.Role_ID);
cmd.ExecuteNonQuery();
}
catch (SqlException)
{
//Handle Exception
}
}
}
Now my problem is, if adding the role goes wrong for whatever reason, I'll have a user created without a role.
So I was wondering if it's possible to join the two SqlCommand, considering that I need the Scope_Identity for the insert into User_Role. Or do a rollback on the last exception catch for both Insert's?
Either make a stored procedure that does the work as an atomic unit, or if you are unable to do that, you can wrap the entire code block in a transaction if yo keep using the same connection, like this:
using (SqlConnection con = new SqlConnection(conString))
{
con.Open();
var transaction = con.BeginTransaction();
try
{
//Run first command
//Run second command
//If we have succeeded, commit the transaction
transaction.Commit();
}
catch()
{
//Something went wrong, roll back
transaction.Rollback();
}
}
Related
I want MySql to insert into a table with the below query,
using (MySqlConnection con = new MySqlConnection(GetC.path))
{
con.Open();
string query = "INSERT INTO `SALES` (ID, QUANTITY, `SOLD AMOUNT`) " +
"VALUES (#id, #qty, #soldamount)";
using (MySqlCommand cmd = new MySqlCommand(query, con))
{
cmd.Parameters.AddWithValue("id",ID);
cmd.Parameters.AddWithValue("qty",quantity);
cmd.Parameters.AddWithValue("soldamount",soldAmount);
status = Convert.ToInt32(cmd.ExecuteNonQuery());
}
con.Close();
}
then update another table with below query immediately 'status' >= 1;
using (MySqlConnection con = new MySqlConnection(GetC.path))
{
con.Open();
string query = "UPDATE PRODUCTS SET QUANTITY=#qty WHERE PRODUCT=#pro";
using (MySqlCommand cmd = new MySqlCommand(query, con))
{
cmd.Parameters.AddWithValue("#qty", newQuanity);
cmd.Parameters.AddWithValue("#pro", product);
cmd.ExecuteNonQuery();
stats = Convert.ToInt32(cmd.ExecuteNonQuery());
if(stats >=1){
//alert successful
}
}
con.Close();
}
My code works fine, until there is internet breakdown, assuming the insertion was successful before internet breakdown, MySql automatically ignore the update and display and error!!
Is there a way to make MySql wait for the internet to continue the update immediately internet is back?
I have simple asp.net web app. That has multiple users who can login and edit Info. However, I have noticed when users are updating info at the same time.When data goes to the MS SQL DB the data is swapped.
Example
UserA was editing Item1, while UserB was editing Item2. On updating the info, it shows UserA was editing Item2.
On login User's Credentials are stored in a session
HttpContext.Current.Session.Add("Username", rs["Username"].ToString());
Code below is used to call the procedure in DB
using (SqlConnection con = new SqlConnection(dc.Con)) {
using (SqlCommand cmd = new SqlCommand("sp_EditItem", con)) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ItemName", SqlDbType.VarChar).Value = txtItemInfo.Text;
cmd.Parameters.Add("#ItemID", SqlDbType.VarChar).Value = txtItemID.Text;
con.Open();
cmd.ExecuteNonQuery();
}
}
Query in the procedure
Update tb_Items
set ItemName = #ItemName
where ItemID = #ItemID
When a single user is updating the data, data is updated correctly.
What causes data to be swapped when multiple users are editing info?
Use SQL Transaction and modify code as below
using (SqlConnection con = new SqlConnection(dc.Con)) {
using (SqlCommand cmd = new SqlCommand("sp_EditItem", con)) {
using (SqlTransaction transaction = connection.BeginTransaction("SampleTransaction"))
{
try
{
cmd.Transaction = transaction;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ItemName", SqlDbType.VarChar).Value = txtItemInfo.Text;
cmd.Parameters.Add("#ItemID", SqlDbType.VarChar).Value = txtItemID.Text;
con.Open();
cmd.ExecuteNonQuery();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
}
}
}
}
Here is what I have written so far.There is no exception so I am assuming the connection is working fine but no data is inserted into the database table. Please tell me what is wrong with my code
SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyETL.Properties.Settings.connectionStr"].ConnectionString);
try
{
conn.Open();
// foreach (student stu in stulist)
// {
string strQuery = "INSERT INTO Student(Sid,st_name) VALUES (#id,#name)";
SqlCommand cmd = new SqlCommand(strQuery, conn);
cmd.Connection = conn;
cmd.Parameters.AddWithValue("#id", "111");
cmd.Parameters.AddWithValue("#name", "nallia");
cmd.ExecuteNonQuery();
}
catch
{
conn.Close();
}
Try this
static void Insert()
{
try
{
string connectionString =System.Configuration.ConfigurationManager.ConnectionStrings["MyETL.Properties.Settings.connectionStr"].ConnectionString;
using (SqlConnection conn =new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("INSERT INTO Student(Sid,st_name) VALUES (" +
"#id,#name)", conn))
{
cmd.Parameters.AddWithValue("#Id", 111);
cmd.Parameters.AddWithValue("#Name", "nallia");
int rows = cmd.ExecuteNonQuery();
//rows number of record got inserted
}
}
}
catch (SqlException ex)
{
//Log exception
//Display Error message
}
}
It has been nearly 2,5 years but if you haven't still solved this problem, you should change the "copy to output directory" attribute to "copy if newer". Your database is changing but every time you start debugging, you read the initial version of database so, you see that there is no changes.
I'm trying to implement an sql transaction, however, i've run into a bit of bother. I have a simple database with has three tables. Users, Post and Comments. I wish to implement a delete button that will delete a user from the Users table. The initial problem I had was that I needed to remove the users FK from both the post and comment table, then remove the user from the User table. I looked online and somebody had suggested using transaction for multiple server calls. Here is my code:
public void DeleteUser(int UserId)
{
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
SqlTransaction sqlTran = con.BeginTransaction();
try
{
using (SqlCommand command = new SqlCommand("DELETE FROM Comment WHERE UserId = " + #UserId, con))
{
SqlParameter userid = new SqlParameter("#UserId", SqlDbType.Int);
userid.Value = UserId;
command.ExecuteNonQuery();
}
using (SqlCommand command = new SqlCommand("DELETE FROM Post WHERE UserId = " + #UserId, con))
{
SqlParameter userid = new SqlParameter("#UserId", SqlDbType.Int);
userid.Value = UserId;
command.ExecuteNonQuery();
}
using (SqlCommand command = new SqlCommand("DELETE FROM Users WHERE UserId = " + #UserId, con))
{
SqlParameter userid = new SqlParameter("#UserId", SqlDbType.Int);
userid.Value = UserId;
command.ExecuteNonQuery();
}
sqlTran.Commit();
}
catch
{
sqlTran.Rollback();
}
}
}
The problem I have is that when the DeleteUser method is run, the program gets as far as the command.ExecutyNonQuery in the first using block, then jumps to the catch. Thus rolling back the changes. There isn't any error codes displayed, so i'm not sure what is going wrong.
Any help in this matter would be greatly appreciated.
You're missing command.Transaction = sqlTran;.
DO NOT USE try {} catch {}. Use at least try {} catch (Exception ex) {} -> this will give you enough information to solve the problem on your own.
I'm curious as to why this is. I ran into this scenario earlier today
using (SqlConnection oConn = new SqlConnection(ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("IC_Expense_InsertCycle", oConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#PortalId", portalId);
cmd.Parameters.AddWithValue("#Description", description);
cmd.Parameters.AddWithValue("#StartDate", start);
cmd.Parameters.AddWithValue("#EndDate", end);
try
{
oConn.Open();
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
throw ex;
}
}
}
//Get the new set of ExpenseCycles for binding
ExpenseCycle cycle = new ExpenseCycle(ConnectionString);
return cycle.GetExpenseCycles(portalId);
// ^^ this works just fine. The GetExpenseCycles call will basically set up the structure above with using SqlConnection and using SqlCommand
using (SqlConnection oConn = new SqlConnection(ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("IC_Expense_InsertCycle", oConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#PortalId", portalId);
cmd.Parameters.AddWithValue("#Description", description);
cmd.Parameters.AddWithValue("#StartDate", start);
cmd.Parameters.AddWithValue("#EndDate", end);
try
{
oConn.Open();
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
throw ex;
}
//Get the new set of ExpenseCycles for binding
ExpenseCycle cycle = new ExpenseCycle(ConnectionString);
return cycle.GetExpenseCycles(portalId);
//This didn't work. The INSERT statement was successful, but it was bringing back old entries, and did not include the newest one that was just inserted
}
}
The bottom code block was initially what I had, and the return count for my test environment was only 1, but there were 2 records in the database. It wasn't fetching that newly inserted record.
The basic code of GetExpenseCycles is the following:
using (SqlConnection oConn = new SqlConnection(ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("IC_Expense_GetExpenseCyclesByPortal",oConn))
{
oConn.Open();
using (SqlDataReader sdr = cmd.ExecuteReader())
{
//Read List<expensecycle> here
}
}
}
Any ideas why? There were no exceptions thrown.
No exceptions thrown so no errors... I suspect the isolation-level on the connection
In the first scenario the connections don't overlap.
ExpenseCycle() use a connection string and I may safely assume it starts a new connection.
In the second example (problem case) the connections do overlap:
If the isolation-level is for instance read-committed and the "enclosing" connection hasn't yet stabilized its write (commit) the new connection don't pick up the changes, in this case the insert.
Possible solutions or things to try out:
1. Check the isolation-level on the connection
2. Pass the connection instead of the connectionstring to ExpenseCycle() (which is a better practice too imho)
You might have an ambient transaction in effect (if the code block is called within the scope of a transaction, new connections will join that transaction automatically. Using the TransactionScope class, you can get a handle of that transaction and commit it before the second call.
Also it looks like your second call is within the scope of the command's using block. Moving it outside of there might be enough to resolve your problem
using (SqlConnection oConn = new SqlConnection(ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("IC_Expense_InsertCycle", oConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#PortalId", portalId);
cmd.Parameters.AddWithValue("#Description", description);
cmd.Parameters.AddWithValue("#StartDate", start);
cmd.Parameters.AddWithValue("#EndDate", end);
try
{
oConn.Open();
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
throw ex;
}
}//close the SqlCommand
//Get the new set of ExpenseCycles for binding
ExpenseCycle cycle = new ExpenseCycle(ConnectionString);
return cycle.GetExpenseCycles(portalId);
//This might fix your problem.
}
The other option is to move the second call outside the using of the first using block like so
bool insertSuccessful;
using (SqlConnection oConn = new SqlConnection(ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("IC_Expense_InsertCycle", oConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#PortalId", portalId);
cmd.Parameters.AddWithValue("#Description", description);
cmd.Parameters.AddWithValue("#StartDate", start);
cmd.Parameters.AddWithValue("#EndDate", end);
try
{
oConn.Open();
cmd.ExecuteNonQuery();
insertSuccessful=true;
}
catch (SqlException ex)
{
insertSuccessful=false
throw ex;
}
}//close the SqlCommand
}//close the connection
//Get the new set of ExpenseCycles for binding
if(insertSuccessful)
{
ExpenseCycle cycle = new ExpenseCycle(ConnectionString);
return cycle.GetExpenseCycles(portalId);
}
I think the first block should fix your problem. If not the second one definitely should.