I know this type of question has been asked at least a dozen times on SO, but I've gone through all the previous questions and answers I could find here and none that I have found apply. I am using several FormView objects on my page and now want to add the option to edit one of them. The FormView is populated by SqlDataSource linked to a stored procedure, so I made a stored procedure to update the records and added it to the SqlDataSource, which now looks like this:
<asp:SqlDataSource ID="TestSqlDataSource" runat="server"
SelectCommandType="StoredProcedure"
ConnectionString="<%$ ConnectionStrings:development %>"
SelectCommand="usp_GetNewTestDetails"
UpdateCommand="usp_UpdateTest"
UpdateCommandType="StoredProcedure"
onupdating="TestSqlDataSource_Updating">
<SelectParameters>
<asp:SessionParameter SessionField="TestID" Name="TestID"/>
</SelectParameters>
<UpdateParameters>
<asp:Parameter Name="testId" Type="Int32"/>
<asp:Parameter Name="testerLicense" Type="Int32" />
<asp:Parameter Name="premiseOwner" Type="String" />
<asp:Parameter Name="premiseAddress" Type="String" />
<asp:Parameter Name="premiseCity" Type="String" />
<asp:Parameter Name="premiseState" Type="String" />
<asp:Parameter Name="premiseZip" Type="String" />
<asp:Parameter Name="protectionType" Type="String" />
<asp:Parameter Name="testType" Type="String" />
<asp:Parameter Name="repairs" Type="String" />
<asp:Parameter Name="notes" Type="String" />
<asp:Parameter Name="testDate" Type="DateTime" />
<asp:Parameter Name="employerName" Type="String" />
<asp:Parameter Name="employerAddress" Type="String" />
<asp:Parameter Name="phoneNumber" Type="String" />
<asp:Parameter Name="emailAddress" Type="String" />
<asp:Parameter Name="dataEntryName" Type="String" />
<asp:Parameter Name="dataEntryPhone" Type="String" />
<asp:Parameter Name="signature" Type="String" />
<asp:Parameter Name="entryDate" Type="DateTime" />
</UpdateParameters>
</asp:SqlDataSource>
When I attempt to update a record, I'm getting an error that says there are too many parameters in my query. I have triple checked that the parameters in my code match exactly (name, number, and even order) to the ones in my stored procedure.
In attempting to find answers, I came across this post which referenced this site (had to go to archive.org because the original appears to be down). I applied what they suggested for adding the parameters to the trace function. What I found was that in my stored procedure, there are a few "lookup" values from the select procedure that aren't in the update procedure. The table I'm trying to update only has the ID of the tester, but the users would like to see their name as well, so it references that table, but in the FormView those fields are read-only during edit mode so they can't attempt to change it. All the other parameters line up... only those lookup values are off.
I thought that by including the specific list of parameters to pass that it would only use those parameters, but that appears to be incorrect. Now I'm stumped because I have already specified the parameters, and I can't see anywhere that they are being overwritten with the ones from the select stored procedure. Where do I tell it not to use those read-only values?
I don't want to remove them from the original stored procedure because they will be needed by the users. The one workaround that I have come up with so far is to add them to the stored procedure and then just never use them. Although I'm fairly certain this would work, it is very much just covering up the problem rather than fixing it.
EDIT: Additional code, per request
This is the method that outputs the parameters to the trace function:
protected void TestSqlDataSource_Updating(object sender, SqlDataSourceCommandEventArgs e)
{
for (int i = 0; i < e.Command.Parameters.Count; i++)
{
Trace.Write(e.Command.Parameters[i].ParameterName);
if (e.Command.Parameters[i].Value != null)
{
Trace.Write(e.Command.Parameters[i].Value.ToString());
}
}
}
This is the stored procedure used for updating:
ALTER PROCEDURE [dbo].[usp_UpdateTest]
#testId INT ,
#testerLicense INT ,
#premiseOwner VARCHAR(50) ,
#premiseAddress VARCHAR(150) ,
#premiseCity VARCHAR(50) ,
#premiseState VARCHAR(2) ,
#premiseZip VARCHAR(10) ,
#protectionType VARCHAR(11) ,
#testType VARCHAR(2) ,
#repairs VARCHAR(200) ,
#notes VARCHAR(300) ,
#testDate DATETIME ,
#employerName VARCHAR(50) ,
#employerAddress VARCHAR(150) ,
#phoneNumber VARCHAR(25) ,
#emailAddress VARCHAR(60) ,
#dataEntryName VARCHAR(50) ,
#dataEntryPhone VARCHAR(25) ,
#signature VARCHAR(50) ,
#entryDate DATETIME
AS
BEGIN
SET NOCOUNT ON;
UPDATE dbo.Tests
SET TesterLicense = #testerLicense ,
PremiseOwner = #premiseOwner ,
PremiseAddress = #premiseAddress ,
PremiseCity = #premiseCity ,
PremiseState = #premiseState ,
PremiseZip = #premiseZip ,
ProtectionType = #protectionType ,
TestType = #testType ,
Repairs = #repairs ,
Notes = #notes ,
TestDate = #testDate ,
EmployerName = #employerName ,
EmployerAddress = #employerAddress ,
PhoneNumber = #phoneNumber ,
EmailAddress = #emailAddress ,
DataEntryName = #dataEntryName ,
DataEntryPhone = #dataEntryPhone ,
Signature = #signature ,
EntryDate = #entryDate
WHERE TestID = #testId
END
Ended up figuring this out on my own. It was related to the fact that Visual Studio created the templates for me based on the stored procedure's schema. When the templates are autogenerated, every textbox in the <EditItemTemplate> section gets generated like this:
<asp:TextBox ID="TestIDTextBox" runat="server" Text='<%# Bind("TestID") %>'/>
Turns out that it is the Bind statement that caused this. VS automatically creates a parameter for any field populated using Bind. Although I was led to believe that the <UpdateParameters> section should have overridden this, it was actually the other way around. I was able to prevent these few read-only fields from passing back their parameters by changing the code on those fields from Bind to Eval:
<asp:TextBox ID="TestIDTextBox" runat="server" Text='<%# Eval("TestID") %>'/>
Works perfectly now.
Addendum:
Found that this causes the same problem in the other direction as well. If you mark a field you don't want edited as Eval but it needs to be included in the update (such as a row ID) it will not work, this time for too few parameters. I'm wondering now what the purpose of the <UpdateParameters> section even is, since it doesn't seem to follow anything in there...
You can delete unwanted parameters during e.g OnDeleting event (e.Command.Parameters.RemoveAt(i)).
I am using ASP.NET and using a grid with the UpdateCommand to update 2 tables
I have the following but doesn't seem to work as I do not get any errors but it simply does not update. From what you can see, am I on the right track?
UpdateCommand="UPDATE [tbl_ProgDt] SET [Type] = #type, [Identifiction] = #samplePoint WHERE [Seq] = #valID UPDATE [tbl_Prog] SET StoreNum = #storeNum WHERE ID = (SELECT ID FROM [tbl_ProgDt] WHERE [Seq] = #valID " >
<UpdateParameters>
<asp:Parameter Name="type" Type="String" />
<asp:Parameter Name="samplePoint" Type="String" />
<asp:Parameter Name="valID" Type="Int32" />
<asp:Parameter Name="storeNum" Type="Int32" />
<asp:Parameter Name="valID" Type="Int32" />
</UpdateParameters>
If you need to do something like that, it would be better to create a stored procedure and wrap the two update sentences using a database transaction
You need to specify:
UpdateCommandType="StoredProcedure" UpdateCommand="Stored Procedure Name"
In your Stored Procedure, something like this:
BEGIN TRANSACTION;
-- your update sentences
COMMIT TRANSACTION;
For a Gridview:
I am trying to use a stored procedure for the first time in a SQLDataSource for the UpdateCommand:
<asp:SqlDataSource ID="TECT_DataSource" runat="server"
ConnectionString="<%$ ConnectionStrings:OracleConnectionString %>"
ProviderName="<%$ ConnectionStrings:OracleConnectionString.ProviderName %>"
SelectCommand="SELECT MPID, User_Id, Last_Name, First_Name
FROM Scripts.vw_Tect_Exam"
UpdateCommand="P_TECT_UPD_EXAM_ID" UpdateCommandType="StoredProcedure">
<UpdateParameters>
<asp:Parameter Name="MPID" Type="Int32" />
<asp:Parameter Name="User_Id" Type="String" />
</UpdateParameters>
</asp:SqlDataSource>
I am wondering how the UpdateParameters get their values set, since I only specify a name?
The procedure P_TECT_UPD_EXAM_ID expects two parameters as input: "in_MPID" and "in_UserId"
I am also wondering how to map those values to the input parameters for the procedure as the names are different?
You can set them something like this :
Example : In the example MPID is the sql parameter name #MPID
<UpdateParameters>
<asp:ControlParameter Name="MPID" ControlID="MPID_TextBox" PropertyName="Text />
<asp:ControlParameter Name="User_Id" ControlID="User_Id_TextBox" PropertyName="Text />
</UpdateParameters>
Correction: Just spotted your proc param names so it must be
<asp:ControlParameter Name="in_MPID" ...............
<asp:ControlParameter Name="in_User_Id" ...............
Hope this helps....
I really wouldn't use a SqlDataSource. It will be much easier if you make the call to the database in the code-behind (or a better yet in a Data Access Layer).
If you use a SqlDataSource the stored procedure call will only be available on that page. Every time you want to make that same call you will have to copy and paste the SqlDataSource or make a UserControl out of it.
The following example uses the Entity Framework to connect to the database and retrieve records:
public List<Record> GetAllRecordsByUserName(string credentials)
{
List<Record> recordList;
using (CustomEntities context = new CustomEntities())
{
IQueryable<Section> recordQuery = from records in context.Records
where records.UserName == credentials
select records;
recordList = recordQuery.ToList<Record>();
}
return recordList;
}
This code is part of a SqlDataSource:
<UpdateParameters>
<asp:Parameter Name="username" Type="String" />
<asp:Parameter Name="first_name" Type="String" />
<asp:Parameter Name="surname" Type="String" />
</UpdateParameters>
How can i code this so i can add multiple parameters, since i can only seem to add one at a time. I do not wish to place these update params in my .aspx file since i wish to seperate my database related items.
SqlDataSourceUsers.UpdateParameters.Add(parameter);
Thanks.
You could place your params in a Dictionary (or list if using parameter objects) and then use a loop to add them...
var params = new Dictionary<string, string>
{
{"param1", "value1"},
{"param2", "value2"},
};
foreach(var param in params)
{
SqlDataSourceUsers.UpdateParameters.Add(
new SqlParameter(param.Key, param.Value)
);
}
I realised a Parameter object does not have a Value property, so how do you assign a value to a parameter?
You use the DefaultValue property, like so:
edsGrantsList.WhereParameters["FileToken"].DefaultValue = txtToken.Text
In this example, my EntityDataSource is called edsGrantsList and it has a where parameter that is defined like this:
<WhereParameters>
<asp:Parameter Name="FileToken" Type="String" DefaultValue="" ConvertEmptyStringToNull="true" />
</WhereParameters>