Author |
Topic |
programer
Posting Yak Master
221 Posts |
Posted - 2010-08-04 : 17:18:46
|
string CreditCardNumberEncrypt = Encrypt(CreditCardNumber.Text); string NameOnCardEncrypt = Encrypt(NameOnCard.Text); MembershipUser myObject = Membership.GetUser(); string UserID = myObject.ProviderUserKey.ToString(); SqlDataSource2.InsertParameters["UserID"].DefaultValue = UserID; // SqlDataSource2.InsertParameters["PaymentId"].DefaultValue = "2"; SqlDataSource2.InsertParameters["PaymentType"].DefaultValue = "dasdasdsa"; SqlDataSource2.Insert(); //Find Max Private key SqlConnection conn = new SqlConnection("data source=.\\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\\aspnetdb.mdf;User Instance=true"); SqlDataAdapter a = new SqlDataAdapter ("select MAX(PaymentId) from tbl_payments;", conn); DataSet s = new DataSet(); a.Fill(s); foreach (DataRow dr in s.Tables[0].Rows) { Label3.Text = (dr[0].ToString()); string PaymentId = (dr[0].ToString()); string year = YYYY.Text; string yearEnd = year.Substring(year.Length - 2); var TestRecords = new[] { new { UserID = UserID, CARDID = PaymentId, Attribute = "Credit card number", Value = CreditCardNumberEncrypt + UserID }, new { UserID = UserID, CARDID = PaymentId, Attribute = "Name on card", Value = NameOnCardEncrypt }, new { UserID = UserID, CARDID = PaymentId, Attribute = "Expiry Date", Value = MM.Text +"/" + yearEnd }}; foreach (var item in TestRecords) { SqlDataSource1.InsertParameters["UserID"].DefaultValue = item.UserID; SqlDataSource1.InsertParameters["CARDID"].DefaultValue = item.CARDID; SqlDataSource1.InsertParameters["AttributeName"].DefaultValue = item.Attribute; SqlDataSource1.InsertParameters["Value"].DefaultValue = item.Value; SqlDataSource1.Insert(); } }First, save the table tbl_Payments. When all the data in a table stored in the column PaymentId (primary key - autoinc).This information is stored in another table tbl_PaymentDetails.Does this make sense?Thanks. |
|
Kristen
Test
22859 Posts |
Posted - 2010-08-05 : 03:57:29
|
"select MAX(PaymentId) from tbl_payments;", conn);...SqlDataSource1.InsertParameters["CARDID"].DefaultValue = item.CARDID;...what happens if another process does the MAX(PaymentId) at the same time as you? Both will try to add the same child records. This method is not ATOMic.I don't know why you are saving Credit Card details in a Key/Value attributes table, but storing them in a table one-row-per-transaction would probably solve this problem, and Key/Value attribute tables are only ever last-resort here. |
|
|
programer
Posting Yak Master
221 Posts |
Posted - 2010-08-05 : 11:12:10
|
quote: Originally posted by Kristen "select MAX(PaymentId) from tbl_payments;", conn);...SqlDataSource1.InsertParameters["CARDID"].DefaultValue = item.CARDID;...what happens if another process does the MAX(PaymentId) at the same time as you? Both will try to add the same child records. This method is not ATOMic.I don't know why you are saving Credit Card details in a Key/Value attributes table, but storing them in a table one-row-per-transaction would probably solve this problem, and Key/Value attribute tables are only ever last-resort here.
How do me recommend?Thanks. |
|
|
spirit1
Cybernetic Yak Master
11752 Posts |
Posted - 2010-08-05 : 12:34:50
|
one way to handle this is to use a SqlTransaction class for your code with the serilizable isolation level.This way your parent and child inserts will happen atomicaly.the thing to watch it here is when you have many (100s) users all purchasing at the same time. But when you reach that level of traffic you usually have to solve other problems first ___________________________________________________________________________Causing trouble since 1980Blog: http://weblogs.sqlteam.com/mladenpSpeed up SSMS development: www.ssmstoolspack.com <- version 1.8 out!SQL Server MVP |
|
|
programer
Posting Yak Master
221 Posts |
Posted - 2010-08-05 : 12:56:36
|
quote: Originally posted by spirit1 one way to handle this is to use a SqlTransaction class for your code with the serilizable isolation level.This way your parent and child inserts will happen atomicaly.the thing to watch it here is when you have many (100s) users all purchasing at the same time. But when you reach that level of traffic you usually have to solve other problems first ___________________________________________________________________________Causing trouble since 1980Blog: http://weblogs.sqlteam.com/mladenpSpeed up SSMS development: www.ssmstoolspack.com <- version 1.8 out!SQL Server MVP
thanks! |
|
|
Kristen
Test
22859 Posts |
Posted - 2010-08-05 : 13:20:18
|
I think risky to do that from the application - if the application pauses between Start Transaction and Commit (or rollback) other users will be locked out.better to do all the SQL in one statement - which either succeeds or fails.One way is to use a stored procedure - one call from your application, the stored procedure can do several steps such as:Begin transactionINSERT into Table1Get IDENTITY number assignedINSERT into Table2 with IDINSERT into Table3 with IDCommitanother way would be to append all the SQL statements into one string variable (in your application) and then send them to SQL Server for execution as a single operation. |
|
|
programer
Posting Yak Master
221 Posts |
Posted - 2010-08-05 : 16:22:06
|
quote: Originally posted by Kristen I think risky to do that from the application - if the application pauses between Start Transaction and Commit (or rollback) other users will be locked out.better to do all the SQL in one statement - which either succeeds or fails.One way is to use a stored procedure - one call from your application, the stored procedure can do several steps such as:Begin transactionINSERT into Table1Get IDENTITY number assignedINSERT into Table2 with IDINSERT into Table3 with IDCommitanother way would be to append all the SQL statements into one string variable (in your application) and then send them to SQL Server for execution as a single operation.
Kristen:What about this way?string connectionString = "data source=.\\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\\aspnetdb.mdf;User Instance=true"; SqlConnection sqlConnection = new SqlConnection(connectionString); sqlConnection.Open(); SqlTransaction sqlTransaction = sqlConnection.BeginTransaction(); SqlCommand sqlCommand = new SqlCommand(); sqlCommand.Transaction = sqlTransaction; string CreditCardNumberEncrypt = Encrypt(CreditCardNumber.Text); string NameOnCardEncrypt = Encrypt(NameOnCard.Text); MembershipUser myObject = Membership.GetUser(); string UserID = myObject.ProviderUserKey.ToString(); SqlConnection dataConnection = new SqlConnection(); dataConnection.ConnectionString = "data source=.\\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\\aspnetdb.mdf;User Instance=true"; dataConnection.Open(); SqlCommand dataCommand = new SqlCommand("INSERT INTO tbl_Payments (UserId, PaymentType) " + "VALUES (@UserId, @PaymentType);SELECT SCOPE_IDENTITY()", dataConnection); SqlParameter myUserId = new SqlParameter("@UserId", UserID); SqlParameter myPaymentType = new SqlParameter("@PaymentType", DropDownList4.Text); dataCommand.Parameters.Add(myUserId); dataCommand.Parameters.Add(myPaymentType); // dataCommand.ExecuteNonQuery(); int UserId = Convert.ToInt32(dataCommand.ExecuteScalar().ToString()); Label3.Text = (UserId.ToString()); string year = YYYY.Text; string yearEnd = year.Substring(year.Length - 2); var TestRecords = new[] { new { UserID = UserID, CARDID = (UserId.ToString()), Attribute = "Credit card number", Value = CreditCardNumberEncrypt }, new { UserID = UserID, CARDID = (UserId.ToString()), Attribute = "Name on card", Value = NameOnCardEncrypt }, new { UserID = UserID, CARDID = (UserId.ToString()), Attribute = "Expiry Date", Value = MM.Text +"/" + yearEnd }}; foreach (var item in TestRecords) { SqlCommand dataCommand2 = new SqlCommand("INSERT INTO tbl_PaymentDetails (UserId, CardId, AttributeName, Value) " + "VALUES (@UserId, @CardId, @AttributeName, @Value)", dataConnection); SqlParameter myUserId2 = new SqlParameter("@UserId", item.UserID); SqlParameter myCardId = new SqlParameter("@CardId", item.CARDID); SqlParameter myAttributeName = new SqlParameter("@AttributeName", item.Attribute); SqlParameter myValue = new SqlParameter("@Value", item.Value); dataCommand2.Parameters.Add(myUserId2); dataCommand2.Parameters.Add(myCardId); dataCommand2.Parameters.Add(myAttributeName); dataCommand2.Parameters.Add(myValue); dataCommand2.ExecuteNonQuery(); |
|
|
spirit1
Cybernetic Yak Master
11752 Posts |
Posted - 2010-08-05 : 17:15:39
|
doing it this way is no improvement than doing it the first way you did it.what Kristen meant was to put all your SQL into one string variable and send that to the SQL Server. but this would be then better implemented by a stored proc.as for your original method you should probably introduce some optimistic concurency via rowversion/timestamp type columnfor the max value.any reason why you're not using an ORM which solves these problems out of the box?___________________________________________________________________________Causing trouble since 1980Blog: http://weblogs.sqlteam.com/mladenpSpeed up SSMS development: www.ssmstoolspack.com <- version 1.8 out!SQL Server MVP |
|
|
programer
Posting Yak Master
221 Posts |
Posted - 2010-08-05 : 17:20:52
|
quote: Originally posted by spirit1 doing it this way is no improvement than doing it the first way you did it.what Kristen meant was to put all your SQL into one string variable and send that to the SQL Server. but this would be then better implemented by a stored proc.as for your original method you should probably introduce some optimistic concurency via rowversion/timestamp type columnfor the max value.any reason why you're not using an ORM which solves these problems out of the box?___________________________________________________________________________Causing trouble since 1980Blog: http://weblogs.sqlteam.com/mladenpSpeed up SSMS development: www.ssmstoolspack.com <- version 1.8 out!SQL Server MVP
spirit1:Did not you think in this way? sqltransaction? |
|
|
spirit1
Cybernetic Yak Master
11752 Posts |
Posted - 2010-08-05 : 17:35:49
|
using a serializable isolation level is a pesimistic concurency option.it will not allow other users to insert new private keys.this way you will always get the max key. the negative effect of this is that while this is happening all other users will have to wait for the transaction to end.Because of that your transaction should span as little lines of code as possible.the problem that Kristen talks about is that the code covered by the transaction can for whatever reason slow down.it's not likely but it can happen due to whatever reasons.The second way is to have a stored procedure that you pass needed data to and you do everything in it.The good thing about it is that you remove the dependency on the application slowness. The serializable transaction isolation level still applies and you have to use begin tran ... commit inside the stored proc.You can also have an optimistic concurency scenario but this gets complex quick. it works basicaly like this:when you get the max private key you alse retreive its rowversion.Rowversion is a special type of column that is unique for the db and is always increasing.when you insert data you have to compare your rowversion with the current max private key rowversion.and complexity just increases from there.In the end it depends how you want your app to behave, what's the expected workload, etc...___________________________________________________________________________Causing trouble since 1980Blog: http://weblogs.sqlteam.com/mladenpSpeed up SSMS development: www.ssmstoolspack.com <- version 1.8 out!SQL Server MVP |
|
|
programer
Posting Yak Master
221 Posts |
Posted - 2010-08-05 : 17:50:01
|
quote: Originally posted by spirit1 using a serializable isolation level is a pesimistic concurency option.it will not allow other users to insert new private keys.this way you will always get the max key. the negative effect of this is that while this is happening all other users will have to wait for the transaction to end.Because of that your transaction should span as little lines of code as possible.the problem that Kristen talks about is that the code covered by the transaction can for whatever reason slow down.it's not likely but it can happen due to whatever reasons.The second way is to have a stored procedure that you pass needed data to and you do everything in it.The good thing about it is that you remove the dependency on the application slowness. The serializable transaction isolation level still applies and you have to use begin tran ... commit inside the stored proc.You can also have an optimistic concurency scenario but this gets complex quick. it works basicaly like this:when you get the max private key you alse retreive its rowversion.Rowversion is a special type of column that is unique for the db and is always increasing.when you insert data you have to compare your rowversion with the current max private key rowversion.and complexity just increases from there.In the end it depends how you want your app to behave, what's the expected workload, etc...___________________________________________________________________________Causing trouble since 1980Blog: http://weblogs.sqlteam.com/mladenpSpeed up SSMS development: www.ssmstoolspack.com <- version 1.8 out!SQL Server MVP
Do you have an example how would I do that? |
|
|
spirit1
Cybernetic Yak Master
11752 Posts |
|
programer
Posting Yak Master
221 Posts |
Posted - 2010-08-05 : 18:09:13
|
quote: Originally posted by programer
quote: Originally posted by spirit1 doing it this way is no improvement than doing it the first way you did it.what Kristen meant was to put all your SQL into one string variable and send that to the SQL Server. but this would be then better implemented by a stored proc.as for your original method you should probably introduce some optimistic concurency via rowversion/timestamp type columnfor the max value.any reason why you're not using an ORM which solves these problems out of the box?___________________________________________________________________________Causing trouble since 1980Blog: http://weblogs.sqlteam.com/mladenpSpeed up SSMS development: www.ssmstoolspack.com <- version 1.8 out!SQL Server MVP
spirit1:Did not you think in this way? sqltransaction?
Is it also available for C #? thanks. |
|
|
programer
Posting Yak Master
221 Posts |
Posted - 2010-08-05 : 18:26:13
|
quote: Originally posted by programer
quote: Originally posted by programer
quote: Originally posted by spirit1 doing it this way is no improvement than doing it the first way you did it.what Kristen meant was to put all your SQL into one string variable and send that to the SQL Server. but this would be then better implemented by a stored proc.as for your original method you should probably introduce some optimistic concurency via rowversion/timestamp type columnfor the max value.any reason why you're not using an ORM which solves these problems out of the box?___________________________________________________________________________Causing trouble since 1980Blog: http://weblogs.sqlteam.com/mladenpSpeed up SSMS development: www.ssmstoolspack.com <- version 1.8 out!SQL Server MVP
spirit1:Did not you think in this way? sqltransaction?
Is it also available for C #? thanks.
Please check out this tutorial: http://www.asp.net/data-access/tutorials/implementing-optimistic-concurrency-csand tell if it is correct.thanks. |
|
|
spirit1
Cybernetic Yak Master
11752 Posts |
Posted - 2010-08-05 : 18:28:05
|
the example on the page? i don't know. but translating it from VB should be straight forward.or google for rowversion concurreny example C# and you should get a few results.___________________________________________________________________________Causing trouble since 1980Blog: http://weblogs.sqlteam.com/mladenpSpeed up SSMS development: www.ssmstoolspack.com <- version 1.8 out!SQL Server MVP |
|
|
spirit1
Cybernetic Yak Master
11752 Posts |
|
programer
Posting Yak Master
221 Posts |
Posted - 2010-08-05 : 18:39:40
|
quote: Originally posted by spirit1 the example on the page? i don't know. but translating it from VB should be straight forward.or google for rowversion concurreny example C# and you should get a few results.___________________________________________________________________________Causing trouble since 1980Blog: http://weblogs.sqlteam.com/mladenpSpeed up SSMS development: www.ssmstoolspack.com <- version 1.8 out!SQL Server MVP
Ok.Just one question:I have one table tbl_Payment. In this table, the UserId, PaymentId, PaymentType ...I have another table tbl_PaymentDetails in this table is UserId, PaymentId, AttributeName, Value.If I TextBox1.text = Credit Card NumberIf I TextBox1.text = Number On NameIt is also possible to store data:AttributeName- Credit Card Number- Number On NameOne-click 'Save'thanks. |
|
|
programer
Posting Yak Master
221 Posts |
Posted - 2010-08-05 : 20:47:11
|
quote: Originally posted by programer
quote: Originally posted by spirit1 the example on the page? i don't know. but translating it from VB should be straight forward.or google for rowversion concurreny example C# and you should get a few results.___________________________________________________________________________Causing trouble since 1980Blog: http://weblogs.sqlteam.com/mladenpSpeed up SSMS development: www.ssmstoolspack.com <- version 1.8 out!SQL Server MVP
Ok.Just one question:I have one table tbl_Payment. In this table, the UserId, PaymentId, PaymentType ...I have another table tbl_PaymentDetails in this table is UserId, PaymentId, AttributeName, Value.If I TextBox1.text = Credit Card NumberIf I TextBox1.text = Number On NameIt is also possible to store data:AttributeName- Credit Card Number- Number On NameOne-click 'Save'thanks.
I understand the code written in App_code.Example:Customer.csexample1.csexample2.csObjectDatasSource use.Am I right? |
|
|
|