Here's how you can use a MS SQL ROWVERSION (TIMESTAMP) column with an asp:SqlDataSource while using Stored Procedures, to handle concurrency.
Set up your SqlDataSource like this:
<asp:SqlDataSource ID="dsRegs" runat="server" OnUpdating="dsRegs_Updating" ConnectionString="[your connstr]" InsertCommand="RegulatoryAgency_Insert" InsertCommandType="StoredProcedure" SelectCommand="RegulatoryAgency_List" SelectCommandType="StoredProcedure" UpdateCommand="RegulatoryAgency_Update" UpdateCommandType="StoredProcedure">
<InsertParameters>
<asp:Parameter Name="RegulatoryCode" Type="String" />
<asp:Parameter Name="RegulatoryName" Type="String" />
<asp:Parameter Name="RegulatoryState" Type="String" />
</InsertParameters>
<SelectParameters>
<asp:Parameter Name="pk_RegulatoryAgency" Type="DBNull" />
</SelectParameters>
<UpdateParameters>
<asp:Parameter Name="pk_RegulatoryAgency" Type="Int32" />
<asp:Parameter Name="RegulatoryCode" Type="String" />
<asp:Parameter Name="RegulatoryName" Type="String" />
<asp:Parameter Name="RegulatoryState" Type="String" />
<asp:Parameter Direction="InputOutput" Name="tsModified" Type="Empty" />
</UpdateParameters>
</asp:SqlDataSource>
The important things to notice are:
- In UpdateParameters, tsModified is the TIMESTAMP value and the Type="Empty".
- OnUpdating is set to the dsRegs_Updating event.
Now the code behind:
/// <summary>
/// When editing for this record/row begins in the grid, we need to get the primary key from the row,
/// and then stuff the TIMESTAMP (tsModified) into a Session variable so it persists
/// </summary>
protected void gvRegs_StartRowEditing(object sender, DevExpress.Web.Data.ASPxStartRowEditingEventArgs e)
{
int pk = (int)e.EditingKeyValue;
var db = new myDataContext();
var ra = db.RegulatoryAgency_List(pk).First();
Session["tsModified"] = ra.tsModified;
}
/// <summary>
/// Before we call the database, convert the Session var back the original Linq-to-SQL type (System.Data.Linq.Binary), then
/// convert it to a (byte) array, and update the SqlDataSource parameter with the correct value.
/// </summary>
protected void dsRegs_Updating(object sender, SqlDataSourceCommandEventArgs e)
{
DbParameter dp = e.Command.Parameters["@tsModified"];
dp.Value = ((System.Data.Linq.Binary)Session["tsModified"]).ToArray();
}
In this example, the front is using a DevExpress ASPxGridView, but the databinding and events should be similar on other databound controls. When the row editing begins, we pull the tsModified value for the record from the database and place it into a Session variable. Then the SqlDataSource fires its Updating event, we grab the Session variable, convert it back to it's original format (in my case a System.Data.Linq.Binary because this example is using Linq-to-SQL), and finally the last trick is that you can't pass the TIMESTAMP value as binary, varbinary, or byte -- is must be sent as btye[], which the .ToArray() is taking care.
With the code like this, I'm able to successfully SELECT, INSERT, UPDATE and DELETE through the SqlDataSource, and the tsModified (TIMESTAMP) value in the database increments as expected.