Trying to update my DB from the edit/update functionality of a GridView. What ever I try, I can't seem to be working.
How can I update my SQLDatasource using the information entered in the GridView edit textbox?
Here is what I have:
.cs:
DS.UpdateCommand = "UPDATE tbSystems SET Systems = #Systems WHERE id = #id";
DS.Update();
.aspx:
<asp:GridView ID="gv1"
runat="server"
CellPadding="2"
DataKeyNames="id"
AutoGenerateDeleteButton="True"
AutoGenerateEditButton="True"
OnRowDeleting="gv1_RowDeleting"
OnRowDeleted="gv1_RowDeleted"
OnRowUpdating="gv1_RowUpdating" OnRowEditing="gv1_RowEditing" OnRowUpdated="gv1_RowUpdated">
</asp:GridView>
<asp:SqlDataSource ID="DS" runat="server" ConnectionString="<%$ ConnectionStrings:conn %>">
<UpdateParameters>
<asp:Parameter Name="Systems" Type="String" />
</UpdateParameters>
</asp:SqlDataSource>
I get this error:
Must declare the scalar variable "#id".
Shouldn't the id variable be declared already since I have it
declared in the DataKeyNames of the GridView or should I create an update parameter in the SQLDataSource?
How do I get the new value in the textbox of the GridView? This line of code always give the old value regardless in which event (edit event, updating event or updated event) I put it in:
Response.Write(((TextBox)gv1.Rows[e.NewEditIndex].Cells[2].Controls[0]).Text);
How do I manage the #variables?
Your help is greatly appreciated.
You don't need any code to connect a GridView to a SqlDataSource control. Just set the relevant properties on the controls and it will just work:
<asp:GridView ID="gv1" runat="server"
DataSourceID="DS"
DataKeyNames="id"
AutoGenerateDeleteButton="True"
AutoGenerateEditButton="True"
/>
<asp:SqlDataSource ID="DS" runat="server"
ConnectionString="<%$ ConnectionStrings:conn %>"
SelectCommand="SELECT * FROM tbSystems"
UpdateCommand="UPDATE tbSystems SET Systems = #Systems WHERE id = #id"
DeleteCommand="DELETE tbSystems WHERE id = #id"
>
<UpdateParameters>
<asp:Parameter Name="id" Type="Int32" />
<asp:Parameter Name="Systems" Type="String" />
</UpdateParameters>
<DeleteParameters>
<asp:Parameter Name="id" Type="Int32" />
</DeleteParameters>
</asp:SqlDataSource>
The important properties are:
DataSourceID - connects the GridView to the SqlDataSource;
SelectCommand - specifies the SQL command used to fill the GridView;
UpdateCommand - specifies the SQL command used to update a record;
UpdateParameters - defines the parameters passed to the UpdateCommand;
DeleteCommand - specifies the SQL command used to delete a record;
DeleteParameters - defines the parameters passed to the DeleteCommand;
With those properties in place, you can get rid of the event handlers in the code-behind. The data source control will take care of everything for you.
ASP.NET Data-Bound Web Server Controls Overview
Data Source Controls Overview
Thanks to the Naveen and lots of tweeking, I finally got to make it work. Here is how I did it. It may not be the best practices but it works.
Put the SQLDataSource in a Session. I don't knkow if this is the right thing to do, however it is the only way I found to catch the value of the gridview edit textbox.
if (!Page.IsPostBack)
{
DS.SelectCommand = "SELECT * FROM tbSystems";
Session["myDS"] = DS;
BindData();
}
Created a BindData function: (gv1 being my GridView)
private void BindData()
{
gv1.DataSource = Session["myDS"];
gv1.DataBind();
}
In the RowEditing function, I've changed the gv1 edit index to the event new edit index.
protected void gv1_RowEditing(object sender, GridViewEditEventArgs e)
{
gv1.EditIndex = e.NewEditIndex;
//Bind data to the GridView control.
BindData();
And this is the update code.
protected void gv1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
DS.UpdateCommand = "UPDATE tbSystems SET Systems = #Systems WHERE id = #id";
var id = gv1.DataKeys[e.RowIndex]["id"];
var systems = ((TextBox)gv1.Rows[e.RowIndex].Cells[2].Controls[0]).Text;
DS.UpdateParameters.Add("id",id.ToString());
DS.UpdateParameters.Add("Systems",systems);
DS.Update();
gv1.EditIndex = -1;
BindData();
}
Hopefully this will help some of you.
Thanks,
Shouldn't the id variable be declared already since I have it declared
in the DataKeyNames of the GridView or should I create an update
parameter in the SQLDataSource?
No. You must fetch the value like this
var id = GridView1.DataKeys[e.RowIndex]["id"];
How do I get the new value in the textbox of the GridView? This line
of code always give the old value regardless in which event (edit
event, updating event or updated event) I put it in
You should be using the RowUpdating event. MSDN sample code here.
How do I manage the #variables?
var systems = ((TextBox)gv1.Rows[e.RowIndex].Cells[2].Controls[0]).Text;
DS.UpdateParameters.Add("#id", id);
DS.UpdateParameters.Add("#Systems", systems);
Related
I have an ASP form created using Telerik's RadGrid control, already binding values from the database and displaying them, with the ability to add and delete entries from the table. I need to add editing functionality, but I've finally run into a block, and I can't find a way past it.
The ASP page contains both the RadGrid and the SqlDataSource I need to use:
<asp:SqlDataSource ID="ContactsSqlDataSource" runat="server"
ConnectionString="<%$ ConnectionStrings:DBConnectionString %>"
SelectCommand="etc..."
UpdateCommand="UPDATE Contacts
SET Salutation=#Salutation,
FirstName=#FirstName,
etc...
WHERE ClientContactID=#ClientContactID" CancelSelectOnNullParameter="False"
onupdating="ContactsSqlDataSource_Updating">
<UpdateParameters>
<asp:Parameter Name="Salutation" Type="String" />
<asp:Parameter Name="FirstName" Type="String" />
etc...
<asp:Parameter Name="ClientContactID" Type="String" />
</UpdateParameters>
<SelectParameters>
<asp:QueryStringParameter Name="GroupID" QueryStringField="ID" />
</SelectParameters>
</asp:SqlDataSource>
etc...
<telerik:RadGrid ID="ContactsRadGrid" runat="server"
AutoGenerateColumns="False" AutoGenerateDeleteColumn="True" CellSpacing="0"
DataSourceID="ContactsSqlDataSource" GridLines="None"
Skin="Windows7" onitemcommand="ContactsRadGrid_ItemCommand"
onitemdatabound="ContactsRadGrid_ItemDataBound"
AllowAutomaticUpdates="True">
<MasterTableView DataSourceID="ContactsSqlDataSource"
DataKeyNames="etc...">
<Columns>
etc...
</Columns>
<EditFormSettings EditFormType="Template">
<FormTemplate>
<asp:HiddenField ID="ClientIDHiddenField" runat="server"
Value='<%# Bind("ClientContactID") %>' />
etc...
<asp:TextBox ID="SalutationTextBox" runat="server" Text='<%# Bind("Salutation") %>' TabIndex="1" />
etc...
<asp:TextBox ID="FirstNameTextBox" runat="server" Text='<%# Bind("FirstName") %>' TabIndex="2" />
</FormTemplate>
</EditFormSettings>
</MasterTableView>
</telerik:RadGrid>
In my code behind, I have:
protected void ContactsRadGrid_ItemCommand(object sender, Telerik.Web.UI.GridCommandEventArgs e)
{
RadGrid grid = sender as RadGrid;
GridDataItem dataItem = e.Item as GridDataItem;
GridEditFormItem editItem = e.Item as GridEditFormItem;
if (e.CommandName == "Delete")
{
etc...
}
else if (e.CommandName == "Update")
{
ContactsSqlDataSource.Update();
}
}
protected void ContactsSqlDataSource_Updating(object sender, SqlDataSourceCommandEventArgs e)
{
GridEditFormItem editItem = (ContactsRadGrid.EditItems[0] as GridDataItem).EditFormItem;
string salutation = Convert.ToString(editItem.GetDataKeyValue("Salutation"));
string firstName = Convert.ToString(editItem.GetDataKeyValue("FirstName"));
etc...
string clientContactID = Convert.ToString(editItem.GetDataKeyValue("ClientContactID"));
e.Command.Parameters["#Salutation"].Value = salutation;
e.Command.Parameters["#FirstName"].Value = firstName;
etc...
e.Command.Parameters["#ClientContactID"].Value = clientContactID;
e.Command.Connection.Open();
e.Command.ExecuteNonQuery();
e.Command.Connection.Close();
}
This is where I finally got to in order to stop getting errors on the SQL execution, however there's one major problem: the values being pushed onto the parameters are the old values, the ones that were already in the database, not the values I've entered in the EditFormItem. If I hardcode something onto a parameter (eg, append ".com" onto email), the alteration is correctly reflected in both the database and the table after the "Save" button in the edit form is clicked. Without the manual edit, no changes occur, because the database is simply being updated with the values that were already present.
How can I get the current values in the edit form?
(I'm not opposed to getting this done in some way other than the DataSource_Updating event, that's just the solution I came up with which was closest to correct. I do need to stick with the RadGrid, though.)
I managed to find a resolution to this issue. In the first part of ContactsSqlDataSource_Updating, I now have:
string salutation = (editItem.FindControl("SalutationTextBox") as TextBox).Text;
string firstName = (editItem.FindControl("FirstNameTextBox") as TextBox).Text;
etc...
string clientContactID = (editItem.FindControl("ClientIDHiddenField") as HiddenField).Value;
The database now updates correctly.
I have a dropdown list to search by categories.
I need help to bind my gridview at page load, but at the same time, I also have a select command as votes.
I know that there are codes such as Databinding in the pageload event. But for my case, i need to link the select command to a button to update votes. If i databind it, i could not grab the data key names to update my votes counter.
Is there any way to bind the gridview, without removing the DataSourceID in the gridview itself?
My aspx codes are as follow.
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:ConnectionString %>"
SelectCommand="SELECT * FROM [Review] WHERE ([Category] = #Category)">
<SelectParameters>
<asp:ControlParameter ControlID="ddlCat" Name="Category"
PropertyName="SelectedValue" Type="String" />
</SelectParameters>
</asp:SqlDataSource>
<asp:SqlDataSource ID="SqlDataSource2" runat="server"
ConnectionString="<%$ ConnectionStrings:ConnectionString %>"
SelectCommand="SELECT [Category] FROM [ReviewCategory]">
</asp:SqlDataSource>
<asp:DropDownList ID="ddlCat" runat="server"
DataSourceID="SqlDataSource2" DataTextField="Category"
DataValueField="Category" AutoPostBack="True"
onselectedindexchanged="SelectionChange">
</asp:DropDownList>
<asp:GridView ID="GridView1" runat="server" Width="1114px"
Height="272px" AutoGenerateColumns="False" PageSize="5"
DataSourceID="SqlDataSource1" AllowPaging="True" DataKeyNames="ReviewID">
<Columns>
<asp:BoundField DataField="Votes" HeaderText="Votes"
SortExpression="Votes" />
<asp:BoundField DataField="Category" HeaderText="Category"
SortExpression="Category" />
<asp:CommandField SelectText="VOTE as your FAVOURITE!"
ShowSelectButton="True" />
</Columns>
c# code
protected void btnVote_Click(object sender, EventArgs e)
{
int reviewid = Convert.ToInt16(GridView1.SelectedDataKey.Value);
SqlConnection conn = new SqlConnection(#"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database.mdf;Integrated Security=True;User Instance=True");
string sqlstmt = "select Votes from Review where ReviewID = '" + reviewid + "'";
SqlCommand comm = new SqlCommand(sqlstmt, conn);
try
{
conn.Open();
SqlDataReader read = comm.ExecuteReader();
if (read.Read())
{
int votes = (int)read["Votes"];
votes += 1;
string updatestatement = "Update Review set Votes= '" + votes + "' Where ReviewID = '" + reviewid + "'";
SqlCommand command = new SqlCommand(updatestatement, conn);
read.Close();
command.ExecuteNonQuery();
}
}
finally {
conn.Close();
GridView1.DataBind();
}
}
protected void SelectionChange(object sender, EventArgs e)
{
int stored = ddlCat.SelectedIndex;
if (stored == 0)
{
SqlDataSource1.SelectCommand = "SELECT * from Review ORDER BY [Votes] DESC ";
}
else { }
}
You should implement the RowCommand event from the GridView. You alredy have the CommandField, so do something like this:
void GridView1_RowCommand(Object sender, GridViewCommandEventArgs e)
{
//
// Get the keys from the selected row
//
LinkButton lnkBtn = (LinkButton)e.CommandSource; //the button
GridViewRow myRow = (GridViewRow)lnkBtn.Parent.Parent; //the row
GridView myGrid = (GridView)sender; // the gridview
int reviewid = Convert.ToInt32(GridView1.DataKeys[myRow.RowIndex].Value); //value of the datakey **strong text**
// If multiple buttons are used in a GridView control, use the
// CommandName property to determine which button was clicked.
// In this case you are pressing the button Select, as ou already
// defined this at the aspx code.
if(e.CommandName=="Select")
{
// Put the logic from btnVote_Click here
}
}
The another way could be implement the SelectIndexChanging or SelectIndexChanged, given that you will use the Select Button to fire the update magic. Here the example with SelectIndexChanging.
void GridView1_SelectedIndexChanging(Object sender, GridViewSelectEventArgs e)
{
// Get the currently selected row. Because the SelectedIndexChanging event
// occurs before the select operation in the GridView control, the
// SelectedRow property cannot be used. Instead, use the Rows collection
// and the NewSelectedIndex property of the e argument passed to this
// event handler.
int reviewid = Convert.ToInt32(GridView1.DataKeys[e.NewSelectedIndex].Value); //value of the datakey **strong text**
// Put the logic from btnVote_Click here
}
Let us look into your requirements one by one:
1.) *Binding GridView at PageLoad with DropDownList:
In this case you need to retrieve the Value selected in dropdownList. Do the below setup to grab the Value from DropDownList
<asp:SqlDataSource ID="SqlDataSource2" runat="server"
ConnectionString="<%$ ConnectionStrings:ConnectionString %>"
SelectCommand="SELECT [Category] FROM [ReviewCategory] where Category=#Category">
<SelectParameters><asp:ControlParameter ControlID="ddlCat" Name="Category"
PropertyName="SelectedValue" /></SelectParameters>
</asp:SqlDataSource>
What is Happenning:
Each time a value is selected in dropdown, Postback will happen( AutoPostback="true").
After the Page.PreRender Event, the DataSource controls [ SqlDatSource here ] performs the required queries and retrieve the data. So the selected DropDownList value will be used by SqlDataSource. Thus there is NO need to worry about changing/manipulating DataSourceID in any way.
2.) "But for my case, i need to link the select command to a button to update votes"
'
In this case you have a Select button inside grid View and a 'vote' button outside GridView but somewhere in your page. So, once you select any row in grid view, click the 'Vote' button. You can access the SelectedRow and Index as usual.
protected void btnVote_Click1(object sender, EventArgs e)
{
int i = CustomersGridView.SelectedIndex;
}
Note that the Click event of 'Vote' button fires before the DataSource controls perform their queries & retrieve data. So once you update the Vote count in btnVote_click event as you are doing currently, there is NO need to Bind data again. This part of your code seems fine to me.
I have a session variable which holds the current logged in user's details. I'd like to run a query based on the variable and display it in a Grid view.
I want to replace the default value of the grid view with the session variable but that didn't work.
Can anyone point me in the right direction?
This is what I tried:
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:..... %>"
SelectCommand="SELECT [Username], [Password], [CustomerName], [CustomerAddress], [Contact] FROM [Customers] WHERE ([Username] = #Username)">
<SelectParameters>
<asp:Parameter DefaultValue="session[new]" Name="Username" Type="String" />
</SelectParameters>
</asp:SqlDataSource>
You can supply the Session variable value just before the Query is executed by SqlDataSource using the Selecting event of the datasource. Set this event in Markup using OnSelecting property.
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:..... %>"
OnSelecting="SqlDataSource1_Selecting"
SelectCommand="SELECT [Username], [Password], [CustomerName], [CustomerAddress], [Contact] FROM [Customers] WHERE ([Username] = #Username)">
<SelectParameters>
<asp:Parameter Name="Username" Type="String" />
</SelectParameters>
</asp:SqlDataSource>
In the Selecting Event Handler, you do as below:
protected void SqlDataSource1_Selecting(object sender, SqlDataSourceSelectingEventArgs e)
{
if(Session["UserName"]!=null)
{
// do this only when Session Variable stores as a string the Username
e.Command.Parameters["#Username"].Value = Session["UserName"];
}
else
{
// assign the default value if session variable is Null
e.Command.Parameters["#Username"].Value ="DefaultValue";
}
}
In this event handler, you can access the command that’s about to be executed through the
SqlDataSourceSelectingEventArgs.Command property, and modify its parameter values programmatically.
What I ended up doing was kind of similar to FlopScientist's answer. I found that the DataSource actually has an option for selecting a session variable which I did in the design view and it has the code below:
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:..... %>"
SelectCommand="SELECT [Password], [CustomerName], [CustomerAddress], [Contact], [Username] FROM [Customers] WHERE ([Username] = #Username)">
<SelectParameters>
<asp:SessionParameter Name="Username" SessionField="mySessionVariable" Type="String" />
</SelectParameters>
</asp:SqlDataSource>
Session object in ASP.NET is one of the server side state maintenance variable.
More you can find here.
Session variable simply stores any value that you assign it to. And in simple words, you can access this variable on any other page, even if you created it on some other page.
so suppose on page1.aspx you did:
Session["uniqueName"] = GetGridViewData(); //you can store anything.
where signature of GetGridViewData() is suppose like:
public DataTable GetGridViewData();
then on page2.aspx (or any other page), you can do this:
protected void Page_Load(object sender, EventArgs e)
{
if(Session["uniqueName"]!=null)
{
//typecast it to your datastructure or whatever you assigned into it
DataTable gridDataSource = (DataTable)Session["uniqueName"];
//any custom logic you want to perform on gridDataSource
gridView1.DataSource = gridDataSource;
gridView.DataBind();
}
}
Just make sure, you access the variable only after you have assigned/created earlier in the flow.
I have two web pages- the first is a GridView and the second is a FormView. I have been able to retrieve the DataKey value from the GridView and pass it to the FormView page. Now I need to use that key value for my selection query. How do I assign that value? Code example would help in C#.
This is my page_load code:
protected void Page_Load(object sender, EventArgs e)
{
string CompanyStr = Server.HtmlEncode(Request.QueryString["param1"]);
string ClientKey = Request.QueryString["param2"];
Label lbl = FormView1.FindControl("CompanyID") as Label;
lbl.Text = CompanyStr;
}
And this is the FormView code:
<asp:FormView ID="FormView1" runat="server" DefaultMode="Insert" DataKeyNames="ClientKey"
DataSourceID="SqlDataSource1" onitemcommand="onItemCommand">
The ClientKey is the variable that needs to be set.
It sounds like you want to use a Select Parameter in your SQLDataSource1 markup (the one referenced in your FormView declaration) to do this. This should work:
<asp:SqlDataSource ID="SQLDataSource1" runat="server"
ConnectionString="Your Connection Strong" SelectCommand="SELECT * FROM [yourTableName] WHERE ClientKey = #ClientKey">
<SelectParameters>
<asp:QueryStringParameter Name="ClientKey" QueryStringField="param2" />
</SelectParameters>
</asp:SqlDataSource>
Notice the WHERE clause in the SelectCommand property. I don't know what the rest of your query looks like, but having that on the end should filter your FormView down to what you want.
This should automatically pull the value from your query string, and your FormView will have the proper record loaded.
I thought calling ObjectDataSource.Select() gives the same results as calling ObjectDataSource.DataBind(), but in some cases that doesn’t seem to be true:
<asp:ObjectDataSource ID="ODS1" TypeName="PersonDB" SelectMethod="GetPeople"
runat="server"></asp:ObjectDataSource>
<br>
<asp:ListBox ID="ListBox1" DataSourceID="ODS1" DataTextField="PersonID"
AutoPostBack="true" runat="server"></asp:ListBox>
<br>
<asp:ObjectDataSource ID="ODS2" InsertMethod="InsertEmployee"
TypeName="PersonDB" SelectMethod="GetPerson" runat="server">
<SelectParameters>
<asp:ControlParameter ConvertEmptyStringToNull="True" Name="PersonID"
PropertyName="SelectedValue" ControlID="ListBox1" />
</SelectParameters>
</asp:ObjectDataSource>
<br>
<asp:DetailsView ID="DetailsView1" AutoGenerateInsertButton="true" DataSourceID="ODS2"
runat="server"> </asp:DetailsView>
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ODS1.Select(); //same as calling ODS1.DataBind();
}
if (IsPostBack)
{
ODS2.Select(); // returns no results
}
}
In the above code calling ODS1.Select() produces the same results as calling ODS1.DataBind(). But if on postback user selects an item in ListBox, ODS2.Select() still doesn’t return any results, but if we replace ODS2.Select(); with ODS2.DataBind(); then a row is returned. So why doesn’t ODS2.Select(); return any results, but ODS2.DataBind(); does?
thank you
EDIT:
Assuming user select an item in a Listbox --> It seems that when we call ODS2.Select(), ODS2 for some reason can't bind to ListBox1.SelectedValue and extract a value from this property
ODS2 has a Select parameter, which in your sample page load is bound to a ListBox control that hasn't been databound. What's in the ListBox? What is being passed in the PersonID parameter that is passed to ODS2?
The most obvious way to start answering your question would be to set a breakpoint in the GetPerson method of PersonDB and see what is being passed as parameters. Then follow the code to see what gets retrieved.