views:

734

answers:

8

I have a forum application using asp.net, c#, sql server and linq to sql. It suffers from multiple inserts, I think when the insert button is pressed but also maybe when the browser is refreshed or back is clicked.

What's the most comprehensive way, or ways to prevent this.

UPDATE: I currently use response.redirect after inserting text. I think maybe the correct approach, upon reading the responses, is to disable the button immediately with javascript? Followed by saving unique value on hidden field (or session?) on the form. Create a field in the db for this value and check this unique value against this field?

Thanks

+7  A: 
  1. Assign a UNIQUE cookie or hidden control to each page
  2. Create a UNIQUE field in your table that holds this cookie or control value.
  3. If a record is inserted with the same cookie, the INSERT will fail and you can process (or ignore) this condition.
Quassnoi
Clutters the database table with transient tokens, although the solution is otherwise correct you only need to store active tokens on the session (server side), not the database - once inserted, remove the token from the session.
JeeBee
A: 

Select a natural primary key from one or more columns of the input data stream. Declare a primary key constraint on the table, using these columns. If you already have a primary key constraint on a surrogate key, and you don't want to remove it, declare a UNIQUE constraint on the natural key instead.

This will cause an error when the application attempts to insert a duplicate row into the table. You will however have to program the app to field the error, and do the right thing.

Walter Mitty
A primary key won't relate to the data being submitted. A surrogate key might, but you wouldn't use this as a primary key.
ck
The table has got a primary key, the problem is if the insert button is clicked a seperate unique entry is submitted with a unique ID
Stuart
A primary key implies a unique constraint. A primary key can be on some autonumber column you create, but it can also be on one or more columns from the input stream. Try it, you might like it!
Walter Mitty
+4  A: 

When I've a page that does inserting or updating I typically do a Response.Redirect to another page after the update is completed, even if you just Response.Redirect to same page. That way if the page is refreshed you aren't re-posting your data.

Dave
Good answer. It is also oftesn worthwhile disabling the button immediately to stop people double-clicking
ck
I agree this is good idea, however, after inserting to the db I want to display the data on the same page, I maybe in hindsight should had the text editor page as a seperate page but I have it embedded on the page and hide / show when text is added
Stuart
This has worked for us as well too.
Mark
@Stuart you can still do a Response.Redirect to the exact same page which is what prevents the double posting
Dave
On checking the code, this is what happens, however the problem still occurs, I think a couple of things might be happening. If the performance is poor, due to client connection, the button is pressed more than once before the redirect. Maybe I should disable the button immediately combined with check unique cookie on insert. This should catch browser refreshes?
Stuart
@Stuart Yes I believe a hybrid of mine and JeeBee's answer would be great, disabling the submit button is common but frowned upon in some circles.
Dave
+2  A: 

Note that your problem isnt really specific to your database. You have a problem with multiple browser requests beeing sent, and you must get around that issue. Either use the redirect pattern as stated above by Dave or use Cookie signing

One example can be found here http://aspalliance.com/711_Preventing_Duplicate_Record_Insertion_on_Page_Refresh_or_Postback_of_a_Web_Form

Nuno Furtado
+1  A: 

use a primary key or unique constraint, if you can't do that I suggest you use the new MERGE statement which will insert if it doesn't exist or update if it does exists (don't know your business rules so that might not work in your situation) MERGE is SQL Server 2008 and up

SQLMenace
merge sounds like a good part of the solution, but only got sql 2005
Stuart
A: 

Assign a unique ID in the form for the comment, and record it with the comment in the database. Perform a check on comments with that unique ID before performing your insert if it doesn't exist.

To allow a user to have several replies on a site active at once, you could allocate the token server-side initially, put that into a list of active posting tokens on the session for that user, put it into the hidden field on the comment form, and only allow a form submission to insert into the database if that token is in the list on the session (and remove it from the list on the session after successfully inserting into the database). This saves you on ever storing the posting token in the database as above, which is a little easier but tatty.

JeeBee
A: 

Put a unique index on the natural key of the data to prevent duplicates from being entered. If required put it against all the fields of the table (except any date oriented ones that would receive the system date at the time of the insert or fields used only by the back end such as insertedby which would contain the user id of the person doing the insertion)except the id.

HLGEM
+2  A: 

Check out this ASP.NET AJAX control called PostBack Ritalin from a fellow SO'r Dave Ward. This could help you with an already tested solution to your javascript disabler idea.

Gavin Miller
I'll check this out, seems appropriate, thanks
Stuart