0

How can I make it so when two people click on the LinkButton at the same time it allows one then prevents the other? I have this form where people are claiming records for themselves but the problem is people click the LinkButton nearly at the same time and then it proceeds to the next page for both of them and they both think the record is theirs.

ASP.NET

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
   <ContentTemplate>
       <asp:Repeater ID="waitingRep" OnItemDataBound="waitingRep_ItemDataBound" 
       OnPreRender="waitingRep_PreRender" OnItemCommand="waitingRep_ItemCommand" 
       runat="server">
         <ItemTemplate>
            <asp:LinkButton ID="claimBtn" OnClick="claim" CommandArgument='<%# Eval("ID") %>' runat="server">
            Claim
            </asp:LinkButton>
         </ItemTemplate>
      </asp:Repeater>
   </ContentTemplate>
</asp:UpdatePanel>

Code Behind

protected void claim(object sender, EventArgs e)
{
        var location = Request.Params["lid"];
        string logon_user = Request.LogonUserIdentity.Name.Substring(7);
        LinkButton claimButton = (LinkButton)(sender);
        int currentID = Convert.ToInt32(claimButton.CommandArgument);

        bool isTaken = false;
        using (SqlConnection conn = new SqlConnection(""))
        {
            SqlCommand cmd = new SqlCommand(@"SELECT COUNT(*) as isTaken FROM ClaimList WHERE ID = '" + currentID + "' AND Status = 2", conn);
            conn.Open();
            SqlDataReader rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                if (Convert.ToInt32(rdr["isTaken"]) > 0) isTaken = true;
            }
            rdr.Close();
        }
        if (!isTaken)
        {
            using (SqlConnection conn = new SqlConnection(""))
            {
                SqlCommand cmd = new SqlCommand(@"UPDATE ClaimList set Status=@f1, ClaimedBy=@f2, ClaimedDate=@f3 where ID=@f4", conn);
                conn.Open();
                cmd.Parameters.Add("@f1", SqlDbType.Int).Value = 2;
                cmd.Parameters.Add("@f2", SqlDbType.Int).Value = logon_user;
                cmd.Parameters.Add("@f3", SqlDbType.DateTime).Value = DateTime.Now.ToString();
                cmd.Parameters.Add("@f4", SqlDbType.Int).Value = currentID;
                cmd.ExecuteNonQuery();
            }
            Response.Redirect("View.aspx?id=" + currentID);
        }
        else
        {
            Response.Redirect("Location.aspx?lid=" + location + "&action=taken");
        }
}
techora
  • 619
  • 3
  • 18
  • 38
  • Well *someone* has to always click it first. Maybe before you redirect just have a `verifyFirst()` method to check the db for the time which the button was pressed? – amza Jul 31 '15 at 14:56
  • look at this solution you have to use either RowLocking or creating / update your data within a Transaction http://stackoverflow.com/questions/19677257/how-to-prevent-two-user-to-access-same-data-from-sql-server – MethodMan Jul 31 '15 at 14:56

1 Answers1

1

Remove the select and add an extra condition to your update to avoid updating if it is already taken, like this:

        bool isTaken = false;
        using (SqlConnection conn = new SqlConnection(""))
        {
            SqlCommand cmd = new SqlCommand(@"UPDATE ClaimList set Status=@f1, ClaimedBy=@f2, ClaimedDate=@f3 where ID=@f4 AND Status <> 2", conn);
            conn.Open();
            cmd.Parameters.Add("@f1", SqlDbType.Int).Value = 2;
            cmd.Parameters.Add("@f2", SqlDbType.Int).Value = logon_user;
            cmd.Parameters.Add("@f3", SqlDbType.DateTime).Value = DateTime.Now.ToString();
            cmd.Parameters.Add("@f4", SqlDbType.Int).Value = currentID;
            if (cmd.ExecuteNonQuery() == 0)
                 isTaken = true;
        }

        if (!isTaken)
             Response.Redirect("View.aspx?id=" + currentID);
        else
             Response.Redirect("Location.aspx?lid=" + location + "&action=taken");
Martín Misol
  • 333
  • 1
  • 7