How's that for an alliteration? I've been meaning to post this tip for a while, since it's something I find myself using quite a bit, but I haven't seen the technique described elsewhere.
Here's the scenario: You have a declarative data source for a control (let's use an example of a DetailsView with a SqlDataSource) and you want to implicitly populate one or more of the parameters when the user inserts a new item. A common example of this is a timestamp field that should be set to whatever time the new row was inserted, and not something populated by the user. This could equally apply to parameter population for select, update, or delete queries too, I just find inserts to be the most common.
There are several parameter types available for declarative data sources, including the ability to draw a value from a cookie, a form field, the user's profile data, a query string, etc. There are occasions, however, where none of these fits the bill and you just need to populate the parameter yourself (like the timestamp case). Another common one is username - if you need to populate a column with a user name in an authenticated site, you need to grab the User.Identity.Name from the context and stuff it in the parameter value of the query.
Anyway, the solution I've been using is to add a handler for the appropriate event on the data source control (the events of interest are Inserting, Selecting, Updating, and Deleting, which are all called before the actual SQL call is made). So to complete the example described above, imagine a bug tracking system where users insert bugs through a DetailsView control, and we want to populate the user field of the defect table with the current user name and the time the bug was submitted with the current time. The following does the trick nicely:
<asp:DetailsView ID="_defectDetailView" runat="server" AutoGenerateRows="False"
DataKeyNames="defect_id"
DataSourceID="defectsDataSource" AllowPaging="True">
<Fields>
<asp:BoundField DataField="defect_id" HeaderText="defect_id"
InsertVisible="False" ReadOnly="True" />
<asp:BoundField DataField="title" HeaderText="title" />
<asp:BoundField DataField="description" HeaderText="description" />
<asp:BoundField DataField="filed_by" HeaderText="filed_by" />
<asp:BoundField DataField="assigned_to" HeaderText="assigned_to" InsertVisible="false" />
<asp:BoundField DataField="severity" HeaderText="severity" />
<asp:BoundField DataField="status" HeaderText="status" />
<asp:BoundField DataField="date_filed" HeaderText="date_filed" InsertVisible="false" />
<asp:CommandField ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
<asp:SqlDataSource ID="defectsDataSource" runat="server"
ConnectionString="<%$ ConnectionStrings:defects_dbConnectionString %>"
InsertCommand="INSERT INTO [defect_reports] ([title], [description], [filed_by], [assigned_to], [severity], [status], [date_filed]) VALUES (@title, @description, @filed_by, @assigned_to, @severity, @status, @date_filed)"
SelectCommand="SELECT defect_id, title, description, filed_by, assigned_to, severity, status, date_filed FROM [defect_reports]"
OnInserting="defectsDataSource_Inserting">
<InsertParameters>
<asp:Parameter Name="title" Type="String" />
<asp:Parameter Name="description" Type="String" />
<asp:Parameter Name="filed_by" Type="String" />
<asp:Parameter Name="assigned_to" Type="String" />
<asp:Parameter Name="severity" Type="String" />
<asp:Parameter Name="status" Type="String" />
<asp:Parameter Name="date_filed" Type="DateTime" />
</InsertParameters>
</asp:SqlDataSource>
And the defectsDataSource_Inserting method that would go in your code behind class:
protected void defectsDataSource_Inserting(object sender,
SqlDataSourceCommandEventArgs e)
{
e.Command.Parameters["@filed_by"].Value = User.Identity.Name;
e.Command.Parameters["@date_filed"].Value = DateTime.Now.ToShortDateString();
}
Note the use of the handy "InsertVisible" property on the BoundField controls in the DetailsView. This makes the field visible only when displaying (or updating) and is perfect for the scenario I'm describing.
So before you resort to manual data binding, remember that you can always influence the execution of any SQL calls made by a declarative data source by adding a handler for the appropriate event.
Posted
Jan 16 2006, 10:13 AM
by
fritz-onion