Hi good day to all. I have this web application for a certain company. In this web application there is a part that uses GridView to display records from the database and the way it is being displayed it is hard coded. I'll display my codes bellow.
string SQLCommand = "SELECT LastName +', ' +FirstName + ' '+MiddleInitial AS 'Name', UserName + ' 'As 'User Name', StreetAddress FROM CustomersMaster Where LastName Like '%"+ SearchText.Text.Trim() + "%'";
SqlCommand com = new SqlCommand(SQLCommand, con);
SqlDataAdapter adp = new SqlDataAdapter(com);
DataTable tbl = new DataTable();
adp.Fill(tbl);
AdminViewBuyersGV.DataSource = tbl;
AdminViewBuyersGV.DataBind();
My problem is I want to use the "Paging" property of the GridView but when I activated the "Paging" property and then when I run it there's an error that says that "The data source does not support server-side data paging". I just want to know how to use paging when I already hard-coded it.
Is there a way on how to solve my problem. Thank You in Advance and God Bless! :)
Make sure you are acting on data...
if (tbl.Rows.Count > 0)
{
AdminViewBuyersGV.DataSource = tbl;
AdminViewBuyersGV.DataBind();
}
else
{
// no records
}
did you write code for the AdminViewBuyersGV_PageIndexChanging routine?
Unless you have a good reason for binding your datasource in code, you might want to look at using a SqlDataSource control in the .aspx page. You can give it a parameter (which is safer than building a sql string the way you are) and it should support paging out of the box...
Ok, so full example using SqlDataSource (as Kendrick mentioned):
First you need to collect the parameters from your query, which it looks like you are already doing in a textbox somewhere. Something like this:
<asp:Label ID="lblLastName" runat="server" AssociatedControlID="tbLastName" Text="Last Name" ClientIDMode="Static" />
<asp:TextBox ID="tbLastName" runat="server" ClientIDMode="Static" />
<asp:Button ID="btnSearch" runat="server" ClientIDMode="Static" Text="Search" />
Now we need to take your Raw Inline SQL out of the code behind and move it into a SqlDataSource. We also want to get rid of the potential SQL Injection you have in your query by using a parameterized query instead :) In order to do that we need to hook up our TextBox to the parameter, but luckily DataSource controls allow us to do this without any code by using SelectParameters.
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:ContactManagerConnectionString %>"
SelectCommand="SELECT LastName + ', ' + FirstName + ' ' + MiddleInitial AS 'Name', UserName AS 'User Name', StreetAddress FROM CustomersMaster WHERE (LastName LIKE '%' + #SearchText + '%')">
<SelectParameters>
<asp:ControlParameter ControlID="tbLastName" ConvertEmptyStringToNull="true"
Name="SearchText" PropertyName="Text" DbType="String" />
</SelectParameters>
</asp:SqlDataSource>
Once those two pieces are in place it is just a matter of setting up your grid the way you want, and setting the AllowPaging property to true.
<asp:GridView runat="server" AllowPaging="True" DataSourceID="SqlDataSource1"
AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="Name" HeaderText="Name" ReadOnly="True"
SortExpression="Name" />
<asp:BoundField DataField="User Name" HeaderText="User Name"
SortExpression="User Name" />
<asp:BoundField DataField="StreetAddress" HeaderText="StreetAddress"
SortExpression="StreetAddress" />
</Columns>
</asp:GridView>
VOILA!
Codeless paging*
* It is worth noting that this is pretty poor in terms of optimization as all the paging work is done on the Web Server. To really make this efficient you would want to employ some paging at the database level. Otherwise you will bring back every record every single time.
It says it doesn't like the data you are binding. So try to tidy the data you are binding:
AdminViewBuyersGV.DataSource = tbl.ToList();
Related
I have a WebForms GridView, where I want to update a BoundField conditionally (or I use a value from a DropDown or I use the text from a Textbox), based on the value from another DropDownList.
<asp:GridView ID="gv_results" runat="server" DataKeyNames="ID_RESULTS" DataSourceID="get_results">
<Columns>
<asp:TemplateField HeaderText="DETAIL" SortExpression="DETAIL">
<EditItemTemplate>
<asp:TextBox ID="tb_detail_edit" runat="server"></asp:TextBox>
<asp:DropDownList ID="dd_detail_edit" runat="server" AutoPostBack="True" DataSourceID="get_detail" DataTextField="DETAIL" DataValueField="DETAIL" ></asp:DropDownList>
</asp:SqlDataSource>
</EditItemTemplate>
<ItemTemplate>
<asp:SqlDataSource runat="server" ID="get_results"
UpdateCommand="UPDATE RESULTS SET [DETAIL] = COALESCE(#DETAIL,#DETAILwelcome)">
<UpdateParameters>
<asp:ControlParameter ControlID="ctl00$MainContent$gv_results$ctl02$dd_detail_edit" PropertyName="SelectedValue" Name="DETAIL" Type="String"></asp:ControlParameter>
<asp:ControlParameter ControlID="ctl00$MainContent$gv_results$ctl02$tb_detail_edit" PropertyName="Text" Name="DETAILwelcome" Type="String"></asp:ControlParameter>
</UpdateParameters>
</asp:SqlDataSource>
Well, I found out in the google's that I have to use the Direct ID in the Control Parameter. And it works...the thing is , the $ctl02 (for example) before the id of the dd_detail_edit, changes, with different rows in the Gridview (so this id works for one row, but maybe for the next it doesn't work.
Is there some workaround for this?
Using only something like $gv_results$dd_detail_edit , doesn't work, I dunno why :S
TIA and Best Regards,
For one thing it looks like you have an open <ItemTemplate> tag without any closing one.
If you check out the .net documentation you can see where they use the regular control IDs, like ControlID = dd_detail_edit.
I do not think you're providing enough details for me to provide a complete answer, but those are a couple of things I noticed.
I'm still a newbie in ASP.NET, and right now, my Gridview is not "updating" when I hit "Update". Here is how I have my GridView w/ the SqlDataSource :
<asp:GridView ID="ProjectTable" runat="server" AutoGenerateColumns="False" AutoGenerateEditButton="True" DataSourceID="PopulateProjectTable" DataKeyNames="ProjectID">
<Columns>
<asp:BoundField DataField="ProjectID" HeaderText="Project ID" ReadOnly="True" SortExpression="ProjectID" />
<asp:BoundField DataField="ProjectDescription" HeaderText="Project Description" ReadOnly="True" SortExpression="ProjectDescription" />
<asp:BoundField DataField="ProjectNotes" HeaderText="Project Notes" SortExpression="ProjectNotes" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="PopulateProjectTable" runat="server" ConnectionString="<%$ ConnectionStrings:sandboxConnectionString %>" SelectCommand="SELECT * FROM [Projects]" UpdateCommand="UPDATE [Projects] SET ProjectNotes = #project_notes">
<UpdateParameters>
<asp:Parameter Name="project_notes" Type="String" />
</UpdateParameters>
</asp:SqlDataSource>
I have no code in the code behind. When I hit "Edit", the third column is suppose to be "editable". When I hit "Update", the page does a postback but what was entered in the third column does not persist and is instead lost. What is going on?
In addition, how would I trace this issue? This is so in the future, I can see what the SQL string is. Thank you.
EDIT: Turns out to be a typo that caused my issue. Problem solved!
Is the spelling correct on the ProjectNotes DataField? The problem you are describing sounds like the field is not bound properly.
I would run SQL profiler while hitting the update. To see what exactly was being sent back to the Database.
You should see your parameter as well. Set the filter to the DB your looking at if you have multiple and give it a try and realtime run the same test by hitting the update button again.
Please modify your update command from this
UpdateCommand="UPDATE [Projects] SET ProjectNotes = #project_notes"
to this
UpdateCommand="UPDATE [Projects] SET ProjectNotes = #project_notes" WHERE ProjectID=#ProjectID
Please add to your DataSource
OnUpdated="OnDSUpdatedHandler">
and add the following method
<script runat="server">
private void OnDSUpdatedHandler(Object source, SqlDataSourceStatusEventArgs e) {
var dbg = e;
}
</script>
Set breakpoint on line
var dbg = e;
and examine what is being in that variable. The answer should be there
Which one is better - Declaring SqlDataSource in ASPX page or in CodeBehind?
Approach #A. As a programmer you can define SqlDataSource in .aspx page such as:
<asp:SqlDataSource ID="Sql_ID" runat="server" ConnectionString="<%$ ConnectionStrings:Con_Str %>"
SelectCommand="SELECT * FROM [table_name]">
<SelectParameters>
<asp:Parameter Name="user_id"/>
</SelectParameters>
</asp:SqlDataSource>
Approach #B. Also, you can do this in C# CodeBehind
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["Con_Str"].ToString()))
{
string qry = SELECT * FROM [table_name];
SqlDataAdapter da = new SqlDataAdapter();
DataTable dt = new DataTable();
using (SqlCommand cmd = new SqlCommand(qry, conn))
{
cmd.Parameters.Add("#user_id", SqlDbType.UniqueIdentifier).Value = user_id;
da.SelectCommand = cmd;
try
{
conn.Open();
da.Fill(dt);
conn.Close();
}
catch
{
// Do something ;
}
}
}
Which Approach [A or B] is better? Why?
Neither.. The best is to separate the data access completely from the UI (to a separate project, or at least namespace, so you can easily swap various implementations if needed). Then, in your code-behind, simply reference the exposed repositories and do the binding. But your code-behind of your pages shouldn't contain any data access.
Try to do some research on 3tier architecture for instance.. Unless it's a very basic application, you should learn how to separate it into multiple layers.
I recommend declaring the SqlDataSource declaratively in the markup and then referencing it in the code-behind, as necessary. For example, if you need to alter the SelectCommand or some other property based upon user interaction or data returned from a service call, etc.
There is no right or wrong way, but you will definitely see the SqlDataSource declared in the markup more often than done in the code-behind, because it is generally easier for people to understand that something in the markup is part of the page than when it is defined in the code-behind, even though they both end up in the generated HTML.
The scenario that makes the most sense to use code-behind to declare things is when you are doing it dynamically and want to be able to add, potentially, more than one of a control.
I wouldn't say one is better. Use the right one depending on what you need to do. If you just need a simple connection, drop it onto the page. If you need to change something conditionally, do it in code.
It would be good to mentioned in code behind. If you are following proper project architect then you need to create DAL (Data access layer),In that case you need to maintain data source in code behind and its easier to mock data source while unit testing.
I would create a DataAccess class which holds all of your logic for calling the data, like:
public class AdoDataAccess : IDataAccess {}
IDataAccess will have your methods, and you can then implement the methods in your concrete class.
Your code behind would then use the IDataAccess, to call an implementation...as in...
IDataAccess dataaccess = new AdoDataAccess(...); <-- this is a lazy way, but just for example purpose.
dataaccess.GetData(...);
This way, if you decide to replace ADO, for maybe EF in the future, you can just add a new DataAcess, like...
public class EFDataAccess : IDataAccess {}
and call it from codebehind
IDataAccess dataaccess = new EFDataAccess(...);
This will help with separation of concern. The way you are looking to implement, doesn't allow for any code-reuse.
CodeBehind is permeable way in case of big and growing system. It will be easy to
support schema changing
change "visibility" logic
add caching
audit and logging
and so on
Of course you may use some kind of ORM.
But if you only need simple CRUD functions declaring is faster.
If the Application is very small and you dont have time for coding then go for sql datasource because you dont have to write a single line of code for that,
also you can insert update and delete data by using Grid view very easily.
<asp:GridView ID="GridView1" CssClass="table table-striped table-bordered table-hover" runat="server" AutoGenerateColumns="False" DataKeyNames="UNQ_ID" DataSourceID="SqlDataSource1" EmptyDataText="No Data has been Added." AllowPaging="True" AllowSorting="True">
<Columns>
<asp:CommandField ShowEditButton="True"></asp:CommandField>
<asp:BoundField DataField="UNQ_ID" HeaderText="UNQ_ID" ReadOnly="True" InsertVisible="False" SortExpression="UNQ_ID" Visible="false"></asp:BoundField>
<asp:BoundField DataField="WucsName" HeaderText="WUCS Name" SortExpression="WucsName"></asp:BoundField>
<asp:TemplateField HeaderText="Year" SortExpression="Year_ID">
<EditItemTemplate>
<asp:TextBox runat="server" Text='<%# Bind("Year_ID") %>' ID="TextBox1"></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<%#YearCON(int.Parse(DataBinder.Eval(Container.DataItem,"Year_ID" ).ToString()))%>
<%-- <asp:Label runat="server" Text='<%# Bind("Year_ID") %>' ID="Label1"></asp:Label>--%>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Total_Land_Holdings" HeaderText="Total Land Holdings" SortExpression="Total_Land_Holdings"></asp:BoundField>
<asp:BoundField DataField="Former_Paying_Cess" HeaderText="Former Paying Cess" SortExpression="Former_Paying_Cess"></asp:BoundField>
<asp:BoundField DataField="Water_Cess_Collected" HeaderText="Water Cess Collected" SortExpression="Water_Cess_Collected">
</asp:BoundField>
</Columns>
<asp:SqlDataSource runat="server" ID="SqlDataSource1"
ConnectionString='<%$ ConnectionStrings:PMISConnection %>'
SelectCommand="SELECT * FROM [tbl_CWLWRK_WaterCess]"
DeleteCommand="DELETE FROM [tbl_CWLWRK_WaterCess] WHERE [UNQ_ID] = #UNQ_ID" InsertCommand="INSERT INTO [tbl_CWLWRK_WaterCess] ([WucsName], [Year_ID], [Total_Land_Holdings], [Former_Paying_Cess], [Water_Cess_Collected]) VALUES (#WucsName, #Year_ID, #Total_Land_Holdings, #Former_Paying_Cess, #Water_Cess_Collected)" UpdateCommand="UPDATE [tbl_CWLWRK_WaterCess] SET [WucsName] = #WucsName, [Year_ID] = #Year_ID, [Total_Land_Holdings] = #Total_Land_Holdings, [Former_Paying_Cess] = #Former_Paying_Cess, [Water_Cess_Collected] = #Water_Cess_Collected WHERE [UNQ_ID] = #UNQ_ID">
<DeleteParameters>
<asp:Parameter Name="UNQ_ID" Type="Int32"></asp:Parameter>
</DeleteParameters>
<InsertParameters>
<asp:Parameter Name="WucsName" Type="String"></asp:Parameter>
<asp:Parameter Name="Year_ID" Type="Int32"></asp:Parameter>
<asp:Parameter Name="Total_Land_Holdings" Type="Int32"></asp:Parameter>
<asp:Parameter Name="Former_Paying_Cess" Type="Int32"></asp:Parameter>
<asp:Parameter Name="Water_Cess_Collected" Type="Int32"></asp:Parameter>
</InsertParameters>
<UpdateParameters>
<asp:Parameter Name="WucsName" Type="String"></asp:Parameter>
<asp:Parameter Name="Year_ID" Type="Int32"></asp:Parameter>
<asp:Parameter Name="Total_Land_Holdings" Type="Int32"></asp:Parameter>
<asp:Parameter Name="Former_Paying_Cess" Type="Int32"></asp:Parameter>
<asp:Parameter Name="Water_Cess_Collected" Type="Int32"></asp:Parameter>
<asp:Parameter Name="UNQ_ID" Type="Int32"></asp:Parameter>
</UpdateParameters>
</asp:SqlDataSource>
For Bigger application you need to use Code behind
HTML
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="id" DataSourceID="SqlDataSource1">
<Columns>
<asp:BoundField DataField="id" HeaderText="id" />
<asp:BoundField DataField="name" HeaderText="name" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:database1ConnectionString %>"
SelectCommand="SELECT * from tblCourse"></asp:SqlDataSource>
Code
SqlDataSource1.SelectCommand =
"SELECT * from tblCourse where name='"+textbox1.text+"'";
SqlDataSource1.DataBind();
But Gridview does not change based on the new select command, even when I'm using DataBind()
How can we change grid view base on select command of sql data source?
This is happening because of GridView's viewstate.
When postback happens, gridview stores its data from ViewState. So, You can either turn off view state for GridView ( a good practice ?? ) OR you call GridView.DataBind() in addition to SqlDataSource.Databind();
METHOD 1: Calling GridView.DataBind();
protected void Page_Load(object sender, EventArgs e)
{
if (this.IsPostBack)
{
string command = SqlDataSource1.SelectCommand; // added just for debug purpose
SqlDataSource1.SelectCommand = "SELECT * from tblCourse where
name='"+textbox1.text+"'";
SqlDataSource1.DataBind();
gridview1.DataBind();
}
}
METHOD 2: Turn off View State for GridView ( Is this a good Practice? ). When you set this false, there is NO need to call GridView.DataBind() in your page_Load as seen in above METHOD 1.
<asp:GridView runat="server" ID="gridview1" EnableViewState="false" ... />
Now the part comes that should must be taken care of::
Make sure the <asp:BoundField> or in general any fields declared and bound to GridView markup are also present in your new query else an error will be thrown saying something similar as below:
A field or property with the name 'ID' was not found on the selected data source
string strSql= "SELECT * from tblCourse where name='abc'";
ViewState["SQL"]=strSql;
SqlDataSource1.SelectCommand =strSql;
SqlDataSource1.DataBind();
Now in the Page_Load
if(IsPostback)
SqlDataSource1.SelectCommand=ViewState["SQL"].ToString();
You can either edit your BoundField's or change the property AutoGenerateColumns to true.
Set autogenerate to true and be sure to remove all the fields in the edit fields wizard. If you change the select command it causes the conflict.
Try adding the following :
SqlDataSource.select(DataSourceSelectArguments.Empty);
before the line SqlDataSource.DataBind();
I have a problem that has been a thorn in my side for nearly a week. I have a site that users can create an account and load videos of there choosing from a database. I would like the videos to show up in a certain order on there page when they look at the ones they selected. My problem is that the videos show up in a random order. I know this may be basic but I am just now entry level (has only been two weeks since I graduated). All the functionality works, so no help needed there, just this darn order thing.
Specs:
Coded in C# ASP.NET
They add and delete selections via checkbox list.
I have the items databound so I can add and remove videos on the back end.
I know this may get me some minus votes, and though I would prefer it not, I just need some help with this issue to be done with the whole project. Before you yell at me for not having code, please tell me what you would like to see so I don't add tons of useless code.
I am not trying to me short, rather I am frustrated that everything I tried won't work.
Thank you in advance.
EDIT:
Here is the SqlDataSource for it:
<asp:SqlDataSource ID="SqlDataSource2" runat="server"
ConnectionString="<%$ ConnectionStrings:fivideoConnectionString %>"
ProviderName="<%$ ConnectionStrings:fivideoConnectionString.ProviderName %>"
InsertCommand="INSERT INTO dealervideo(DealerRecID,VideoRecID) VALUES (?,?)"
DeleteCommand="DELETE FROM dealervideo where RecID = ?" >
<DeleteParameters>
<asp:SessionParameter Name="recid" SessionField="videorecid" />
</DeleteParameters>
<InsertParameters>
<asp:ControlParameter ControlID="hidRecID" Name="recid" PropertyName="Value" />
<asp:SessionParameter Name="videorecid" SessionField="videorecid" />
</InsertParameters>
</asp:SqlDataSource>
And here is the Gridview:
<asp:GridView ID="GridView2" runat="server"
DataSourceID="SqlDataSource2" AutoGenerateColumns="False"
DataKeyNames="RecID" CellSpacing="5" BorderStyle="None" BorderWidth="0px">
<Columns>
<asp:TemplateField HeaderText="Delete">
<ItemTemplate>
<asp:CheckBox ID="cbDelete" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" />
</Columns>
</asp:GridView>
And this is the event when they click to add a video to the list:
protected void btnAddVideo_Click(object sender, EventArgs e)
{
foreach (GridViewRow gvr in GridView3.Rows)
{
CheckBox chkItem = (CheckBox)gvr.FindControl("cbAdd");
if (chkItem.Checked)
{
String sRecID = GridView3.DataKeys[gvr.RowIndex].Value.ToString();
Session["videorecid"] = sRecID;
SqlDataSource2.Insert();
SqlDataSource2.SelectCommand = "SELECT * FROM dealervideo inner join videos on videos.RecID = dealervideo.VideoRecID inner join dealers on dealers.RecID = dealervideo.DealerRecID where dealers.RecID = " + hidRecID.Value;
}
}
GridView2.DataBind();
Add an "ORDER BY" to your Select Command and the field which you want it to be ordered on.
Example:
SqlDataSource2.SelectCommand = "SELECT * FROM dealervideo inner join videos on videos.RecID = dealervideo.VideoRecID inner join dealers on dealers.RecID = dealervideo.DealerRecID where dealers.RecID = " + hidRecID.Value + " ORDER BY videos.RecID";
I assume you are binding to the results of a stored procedure or sql command? In that case, why not use an "Order By" clause in your SQL statement? The items will be displayed in the order in which they are pulled from the database.