ASP.NET SelectParameter / Control Parameter usage - asp.net

newbie to asp.net here.
I am trying to setup a selectparameters and controlparameters based off textbox web controls for date ranges to retrieve data on a asp.net page.
SelectCommand="SELECT SUM(Turnover) AS TotalTurnover, (SUM(Turnover) / (SELECT COUNT(*) FROM (SELECT DISTINCT [Trade Date] FROM TradeSummary WHERE ([Trade Date] BETWEEN #T1 AND #T2)))) AS AverageTO FROM TradeSummary WHERE ([Trade Date] BETWEEN #T1 AND #T2)">
<SelectParameters>
<asp:ControlParameter ControlID="TradeDate1" DefaultValue="8-10-2012" Name="T1" Type="DateTime" PropertyName="Text" />
<asp:ControlParameter ControlID="TradeDate2" DefaultValue="8-11-2012" Name="T2" Type="DateTime" PropertyName="Text" />
</SelectParameters>
TradeDate1 and TradeDate2 refer to 2 textbox controls that I setup for date picking.
I am wondering how I can examine the values of #T1 and #T2 so that I can ensure the query being passed to the DB is valid because it seems like if I were to eval("TotalTurnover") then I get a dbnull error.
Any help would be appreciated. Thanks!

you can also pass the control paraamters from your code behind after checking the values. Add the below code in your Page_Load or any other control event ( e.g button )
// check your textbox values
if( TradeDate1.Text != null )
{
SqlDataSource1.SelectParameters.Add("#T1",TradeDate1.Text);
}

I'd check the input values of the textboxes on a click event of a button and if they're all ok go on the databind the datasource. Then on the selecting event of the datasource I'd set the parameters necessary by using datsource.SelectParameters["T1"].DefaultValue = date;

Related

asp:SqlDataSource with ROWVERSION (TIMESTAMP)

I ran into .NET (Framework, w/ WinForm and WebForms) / MS SQL project where significant tables in the database contain a TIMESTAMP (aka ROWVERSION) column (called tsModified) to prevent concurrency issues. Additionally, this project does not allow the application layer to interact directly with the tables (instead all CRUD and business logic must be done through Stored Procedures).
One of the things that has been driving me crazy is how to use an SqlDataSource that can account for the TIMESTAMP column during UPDATE.
The basic form of the CRUD procs are like this:
CREATE PROC Customer_List
#pk_Customer INT = null
SELECT id, name, tsModified
FROM Customer
WHERE #pk_Customer IS NULL OR #pk_Customer = id;
CREATE PROC Customer_Update
#id INT,
#name varchar,
#tsMod TIMESTAMP
IF NOT EXISTS (SELECT TOP 1 1 FROM Customer where id=#id and tsModified=#tsModified)
Return; --actually RAISEERROR w/ a concurrency alert telling the user to refresh & try again
UPDATE Customer SET [param/value pairs] WHERE id = #id;
Sure, you could manually define partial classes and methods to account for tsModified, and then use asp:ObjectDataSource, but that is extra work. I just want the convenience of dropping an asp:SqlDataSource on the form, and get on with my day.
BUT... the SqlDataSource does not like the TIMESTAMP as a parameter. In fact, I've literally spent days researching how to make this work, and ran into plenty of others having the same issue.
I finally figured it out. See answer below.
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.

How can I populate an Asp.net dropdown using a sqldatasource which has the connectionstring bound at runtime?

So, I've been fighting with this for more time than I'd like to admit, and can't seem to find info on what I'm doing wrong. So, humbly, I submit this question.
I have 2 dropdowns and datasources as defined here:
<asp:DropDownList ID="ddAdminYear" runat="server" enabled="false" DataTextField="YEAR_ID" DataValueField="YEAR_ID" AutoPostBack="True" AppendDataBoundItems="true">
<asp:ListItem Text="----------" Value="----------" /></asp:DropDownList>
<asp:SqlDataSource ID="sdsAdminDistinctYr" runat="server"
ProviderName="System.Data.SqlClient" SelectCommand="SELECT DISTINCT YEAR_ID FROM PC_YEAR ORDER BY YEAR_ID" DataSourceMode="DataReader"></asp:SqlDataSource>
<asp:DropDownList ID="tbOneUnit" runat="server" AutoPostBack="True"
DataTextField="LONG_DESC" DataValueField="SHORT_DESC_EN" AppendDataBoundItems="True" Enabled="True">
<asp:ListItem Text="----------" Value="----------" /></asp:DropDownList>
<asp:SqlDataSource ID="sdsAdminMunic" runat="server" Onselecting="eventselect" ProviderName="System.Data.SqlClient" SelectCommand="GET_MUNIC_LISTING_VB" SelectCommandType="StoredProcedure" >
<SelectParameters>
<asp:controlparameter DefaultValue="2017" Name="year" controlid="ddAdminYear" propertyname="SelectedValue"/>
<asp:Parameter DefaultValue="default" Name="region" Type="String"/>
<asp:Parameter DefaultValue="default" Name="u_r" Type="String"/>
<asp:Parameter DefaultValue="default" Name="UserGroup" Type="String"/>
</SelectParameters>
</asp:SqlDataSource>
The connectionString for sdsAdminDistinctYr is set when the page loads. The code that runs looks like this:
sdsAdminDistinctYr.ConnectionString = _user.SelectedDBConn
ddAdminYear.DataSourceID = "sdsAdminDistinctYr"
Then, in the select event handler for ddAdminYear, I set the datasource for tbOneUnit as follows:
sdsAdminMunic.ConnectionString = _user.SelectedDBConn
tbOneUnit.DataSourceID = "sdsAdminMunic"
tbOneUnit.DataBind()
The ddAdminYear dropdown populates, however, the tbOneUnit dropdown does not.
How can I get the tbOneUnit dropdown to populate using a stored procedure based on the ddAdminYear value?
EDIT:
I can't post the stored procedure itself, but here's the header:
[dbo].[GET_MUNIC_LISTING_VB] (
#YEAR smallint,
#REGION as varchar(5) = NULL,
#U_R as varchar(2) = NULL,
#USERGROUP as varchar(10) = NULL)
I can verify it returns data.
Let me know if anything else would be helpful.
Edit #2:
The stored procedure is running, but the "default" values are being passed as strings (which I had specified)... So, that's not what I want to do.
Right now the application will pass something like :
exec GET_MUNIC_LISTING_VB #year=N'2017',#region=N'default,N'#u_r=N'default',#UserGroup=N'default'
To the application, whereas I'd like it to pass:
exec GET_MUNIC_LISTING_VB #year=N'2017',#region=default,#u_r=default,#UserGroup=default
I would approach the problem one of two ways depending on how much data you will need for all possible combinations of data for the two drop downs.
If you have a limited number of values for ddAdminYear I would create a tbOneUnit for each value, then I would dynamically show or hide each of these drop downs based on the selected value using some javascript. You would need to create a foreach loop and unique Id or some other identifier so that you could identify each unique drop down.
$(document).ready(function() {
$('#ddAdminYear').change(function() {
var adminYear = $(this).val();
$('.tbOneUnit').hide();
$('#tbOneUnit_' + adminYear).show();
});
});
If you have too much data for solution above, then another solution would be to create an ajax event every time the ddAdminYear changed, and use that to populate the data for tbOneUnit. This of course would require you to write a method on from the server that would return the correct data for tbOneUnit based on the current value of ddAdminYear.
$(document).ready(function() {
$('#ddAdminYear').change(function() {
var adminYear = $(this).val();
var get = $.ajax('/GetTbData', adminYear);
get.done(function(data) {
// take data and add to drop down here
});
});
});
So, it looks like my issue is that I was specifying parameters for executing a stored procedure, when I wanted to use the defaults defined in the stored procedure.
I was able to fix this by commenting out the parameters I had specified, leaving only the ddAdminYear controlParameter. This produced the following code RPC:
exec GET_MUNIC_LISTING_VB #year=N'2017'
Thanks to everyone who posted, and put in an effort.

Repeater in ASP.NET - Trying to connect it with a datasource that calls a SP on SelectCommand, getting multiple errors

I have a stored procedure to list items on my database that receives the 'user_mail' parameter. I want to display the results on a repeater but the combination of declaring a parameter and the loop nature of the repeater is causing me problems.
See I have the following code:
<asp:SqlDataSource ID="SqlLogList" runat="server" ConnectionString="<%$ ConnectionStrings:LocalSqlServer %>"
SelectCommand="ws_log_list">
<SelectParameters>
<asp:Parameter Name="user_mail" DefaultValue="ALL" />
</SelectParameters>
</asp:SqlDataSource>
On code behind if I use the following code, clearing the parameters,I get an error saying there's a parameter that needs to be declared. If I remove the .Clear() I get an error saying the parameter user_mail is being declared multiple times!
SqlLogList.SelectParameters.Clear();
SqlLogList.SelectParameters.Add("user_mail", "bomb#cryo.com.br");
repeater.DataSource = SqlLogList;
repeater.DataBind();
Then don't add it again... just set it:
SqlLogList.SelectParameters.Clear();
SqlLogList.SelectParameters["user_mail"].Value = "bomb#cryo.com.br");
repeater.DataSource = SqlLogList;
repeater.DataBind();
Your syntex is wrong, missing # for parameter name. It should be:
SqlLogList.SelectParameters.Add("#user_mail", "bomb#cryo.com.br");

ASP Master pages: How to pass a value from a child page to a SqlDataSource parameter on a master page

Here's a puzzle. A datasource on a master page refers for its SelectParameter to a label control containing some text on a (grand)child page:
<asp:SqlDataSource ... SelectCommand="SELECT * FROM [tblMyTable] WHERE (([strField] = ?) ">
<SelectParameters>
<asp:ControlParameter Name="strField" ControlID="cphMaster$cphChild$lblGrandchild" propertyname="Text" DbType="String"/>
</SelectParameters>
</asp:SqlDataSource>
but this generates an error ("System.Data.OleDb.OleDbException: Data type mismatch in criteria expression.")
I've checked the obvious (strField really is a string, the ContentPlaceHolder (cph) controls are correctly identified by their IDs). Any ideas?
And is my basic approach of 'ControlParameter reading a control placed in a ContentPlaceholder(s)' a reasonable way of passing a value into a SelectParameter?
I will suggest you to create a public property with type SQLDataSource on your master page class that can be accessed to your child page.
YourMasterPage.vb (class name of master page is YourMasterPage)
Private _mastersqldatasource as SqlDataSource
Public ReadOnly Property MasterSQLDataSource() As SqlDataSource
Get
Return SqlDataSource1
End Get
End Property
Then you can access it to your child page
dim myMasterPage as YourMasterPage
myMasterPage = DirectCast(Me.Page.Master, YourMasterPage)
myMasterPage.MasterSQLDataSource.SelectParameters("strField").DefaultValue = lblGrandChild.Text
Hope this helps, I used to use this way for your case
You can use following code in your child page .cs file .
SqlDataSource ds = this.MasterPage.FindControl("datasourceid");
// now you can custimize this ds according to your problem
It turns out that my method is fine. In my real application I had several criteria, and the problem was that the SelectParameters were not in the same order as the criteria in the WHERE clause. When the order is the same, the method works.
So:
SELECT * FROM [myTable] WHERE [FieldA] = ? AND [FieldB] = ? AND [FieldC] = ?
needs:
<SelectParameters>
<asp:ControlParameter Name="FieldA" ControlID="cphMaster$cphChild$lblGrandChildA .../>
<asp:ControlParameter Name="FieldB" ControlID="cphMaster$cphChild$lblGrandChildB .../>
<asp:ControlParameter Name="FieldC" ControlID="cphMaster$cphChild$lblGrandChildC .../>
</SelectParameters>
ie, not ACB, etc. I've never before come across this behaviour, which may arise from the master/child(/grandchild) structure. Hope this helps others.
Congratulation it seems you able to fix the issue. If you allow your users to use some various browsers (e.g: IE, Firefox, Chrome, Safari).
You might need to check whether cphMaster$cphChild$lblGrandChildA is the same generate ID for your control, in some browser it will rendered as cphMaster_cphChild_lblGrandChildA with underscore, but if you only allow your user to use only one browser, then it will not be an issue.

ASP.NET SqlDataSource set SessionParameter programmatically

I have a StoredProcedure called "usp_posts_getall" and it has 1 parameter called "#thisCategoryID"
in my "thisCategoryID", any values other than 0(zero) will return all the records in my Posts table.
Now I have a category menu items and each time I select, I set the value in my Session name called "SelectedCID".
So, How do I ...
Create a SessionParameter Programmatically in SqlDataSource?
UPDATE:
ok. I got it working now.
If it's a session parameter that's used by the SqlDataSource, then you can set the value in the session, e.g in Page_Load():
Session["thisCategoryID"] = theCategoryId;
(am I misunderstanding the question?)
Ok, update:
I think you can create an event handler for the SqlDataSource.OnSelecting event. In that handler, you can access the Parameters collection of the datasource and can add another Parameter to it. I currently cannot test the following code, so it might not be fully correct, but I hope you see the idea:
SqlDataSource1_OnSelecting(SqlDataSourceSelectingEventArgs args)
{
var param = new Parameter("#thisCatagoryID");
param.DefaultValue = Session["SelectedCID"];
SqlDataSource1.SelectParameters.Add(param);
}
Alternatively, you can set the parameter declaratively in the markup, e.g:
<asp:SqlDataSource ...>
<SelectParameters>
<asp:SessionParameter Name="thisCategoryID" SessionField="SelectedCID"
DefaultValue="0" />
...
</SelectParameters>
</asp:SqlDataSource>

Resources