sql-server-2008-r2thread-safetyunique-constraintrazor-3

How can I avoid duplicate rows from near-simultaneous SQL adds?


My Razor 3 web app is creating multiple rows for the same foreign key Id, when multiple input comes in for the same Id, and I would like help on how to avoid this.

The SQL Server table stores data about records in another table (it's ratings users have given about certain things, where there is also a table of users and a table of rate-able things, so the ratings table has a foreign key id for user, a foreign key id for the thing rated, and a value for the rating). When no rating has been given, there is no row for that user id & thing id.

When a user rates a thing, the code calls the server, which checks to see if that user has rated that thing before, and if so, it updates the row, but if not, it creates a new row:

// Get the member's rating for the thing, or create it.
Member_Thing_Rating memPref = (from mip in _myEntities.Member_Thing_Rating
                               where mip.thingID == thingId
                               where mip.MemberID == memberId
                               select mip).FirstOrDefault();
if (memPref == null)
{
   memPref = new Member_Thing_Rating();
   memPref.MemberID = memberId;
   memPref.thingID = thingId;

   _myEntities.Member_Thing_Rating.AddObject(memPref);
}

Which works fine EXCEPT when the user sends two ratings for the same thing very quickly (which happens rather often), which results in the server creating two rows, because apparently it is multi-threaded and neither thread sees an existing row, so they both create a new one.

So... how can I avoid this?

or

I just don't know the syntax or UI/SQL steps to do either, despite a bit of looking. I think I prefer the thread lock solution, because I am more programmer than DB person, so I prefer my complexity in the code.

Thanks for any help!


Solution

  • You could easily add a unique constraint to your SQL Server table to make sure you never get duplicates on your (memberID, thingID) columns:

    ALTER TABLE dbo.YourTableNameHere
    ADD CONSTRAINT UQ_MemberID_ThingID UNIQUE(MemberID, ThingID)
    

    Now, if your second connection tries to insert a row with values for (MemberID, ThingID) that are already in the table, the INSERT will fail, you'll get an exception which you can handle and e.g. get new values for one or both of those ID's.