Insert/Update/Delete on GridView generated by Entity Framework - c#

I'm using EF 6.1.3 and SQL server 2014 for this ASP.NET Web Forms application. I drag&dropped a gridview on my .aspx page design view and used Smart Tag to choose my data source and automatically fill the grid. I enabled edit and delete operations on gridview and it works with no problem but I want it to use the functions I wrote.
This is what I tried for delete operation
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Delete")
{
int rowIndex = Convert.ToInt32(e.CommandArgument);
Result<Models.UserList> result;
using (ModelOperations.UserList.IUserListOperations dao = new ModelOperations.UserList.UserListOperations())
{
result = dao.removeUser(new Models.UserList()
{
ID = Convert.ToInt32((GridView1.Rows[rowIndex].Cells[1].Text))
});
}
}
}
It actually works but the page gives an error. The method in my UserListOperations have a try-catch block but there is no exception caught because the code is simply working.
This is the GridView code generated by EF
<asp:GridView ID="GridView1" runat="server" OnRowCommand="GridView1_RowCommand" AllowSorting="True" AutoGenerateColumns="False" DataKeyNames="UserID" DataSourceID="myEntities">
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<asp:BoundField DataField="UserID" HeaderText="UserID" ReadOnly="True" SortExpression="UserID" />
<asp:BoundField DataField="UserName" HeaderText="UserName" SortExpression="UserName" />
<asp:BoundField DataField="UserPW" HeaderText="UserPW" SortExpression="UserPW" />
<asp:BoundField DataField="UserType" HeaderText="UserType" SortExpression="UserType" />
</Columns>
</asp:GridView>
And this is the error
Store update, insert, or delete statement affected an unexpected
number of rows (0). Entities may have been modified or deleted since
entities were loaded. Refresh ObjectStateManager entries.
If I take the values from textbox and send values that way, there is no error so I'm guessing it's something about the auto-generated grid.

Related

LinqDataSource does not support the Select property when the Delete

I have LinqDataSource that being attached to GridView In Asp.net web application.
<asp:LinqDataSource ID="LinqDataSource1" runat="server" ContextTypeName="DataClassesDataContext" OnInit="LinqDataSource1_Init"
EnableDelete="True"
EntityTypeName="Id" TableName="CompanysCourses"
OnDeleting="Course_Deleting" OnDeleted="Course_Deleted">
</asp:LinqDataSource>
Within OnInit event I have modified the select and where properties like that
this.LinqDataSource1.Where = "CompanyId == " + UserManager.CompanyId;
this.LinqDataSource1.Select= "Course";
I am selecting table named CompanysCourses and after that filter the result and select specific courses based on company's ID
And this is my grid view
<asp:GridView ID="grdVwCourses" runat="server"
AllowPaging="True" AllowSorting="True"
AutoGenerateColumns="False"
DataKeyNames="Id" DataSourceID="LinqDataSource1"
OnSelectedIndexChanged="grdVwCourses_SelectedIndexChanged"
CssClass="table table-responsive"
PageSize="10" GridLines="Horizontal"
meta:resourcekey="GridView1Resource1">
<EmptyDataTemplate>
<asp:Label runat="server" ID="NotFoundLabel" Text="" meta:resourcekey="NotFoundLabelResource1"></asp:Label>
</EmptyDataTemplate>
<Columns>
<asp:TemplateField HeaderText="#" meta:resourcekey="HeaderId">
<ItemTemplate>
<%# Container.DataItemIndex + 1 %>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Id" Visible="false"/>
<asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" meta:resourcekey="BoundFieldResource1" />
<asp:BoundField DataField="EnglishName" HeaderText="EnglishName" SortExpression="EnglishName" meta:resourcekey="BoundFieldResource2" />
<asp:BoundField DataField="CreatedDate" HeaderText="CreatedDate" SortExpression="CreatedDate" meta:resourcekey="BoundFieldResource3" />
<asp:TemplateField meta:resourcekey="TemplateFieldResource1">
<ItemTemplate>
<asp:HyperLink ID="userLink" runat="server" NavigateUrl='<%# GetCategoriesLink(Eval("Id")) %>' Text="Categories" meta:resourcekey="userLinkResource1" />
</ItemTemplate>
</asp:TemplateField>
<asp:CommandField ShowSelectButton="True" ShowDeleteButton="True" meta:resourcekey="CommandFieldResource1" />
</Columns>
</asp:GridView>
I have in the grid view enabled deleting but when click delete I got this exception
LinqDataSource 'LinqDataSource1' does not support the Select property
when the Delete, Insert or Update operations are enabled.
I have override On_Deleting event like that to show confirmation dialog
protected void Course_Deleting(object sender, LinqDataSourceDeleteEventArgs e)
{
e.Cancel = true
this.panMessage.Visible = true;
int id = ((Course)e.OriginalObject).Id;
ViewState["DeleteObject"] = id;
}
I wonder what is the reason of this problem.
Edit
The question referred to as duplicate to mine doesn't have the answer that I seek, also the details are different.
I came today to the same issue on some legacy project, as the error showing this widget doesn't support deleting when you use SELECT statement.
so the solution is to remove your select statement from this datasource, ie remove this line:
this.LinqDataSource1.Select= "Course";
then on the gridview change DataKeyNames to your table Id name and also change the navigation property to access the fields, for example Course.Id, Course.Name etc for each columns in the fields.
the last thing is to cast to the main table and use the any field to access the Id of that table child value.
int id = ((Course)e.OriginalObject).Id;

Getting name of table columns in gridview in addition to custom names

I have a simple grid on my ASPX page and I am binding it with data coming from a select query on button click event. I am not sure how to bind columns of this table with my grid as currently I am getting 8 columns, 4 with the header given in aspx page and 4 with headers of table columns. Below is my button click event code.
protected void btnSearch_Click(object sender, EventArgs e)
{
MyBookListCont myBookListCont = new MyBookListCont();
gdvMyBooks.DataSource = myBookListCont.SearchBookDetailsCont();
gdvMyBooks.DataBind();
}
And below is aspx code of gridview.
<asp:GridView ID="gdvMyBooks" runat="server">
<Columns>
<asp:BoundField DataField="BK_NM" HeaderText="Book Name" />
<asp:BoundField DataField="ATHR_NM" HeaderText="Author Name" />
<asp:BoundField DataField="BUY_YR" HeaderText="Buy Year" />
<asp:BoundField DataField="PRICE" HeaderText="Price" />
</Columns>
</asp:GridView>
Looks like a silly question, but help would be much appreciated.
This is because you have explicitly specified 4 columns in this design code :
<Columns>
<asp:BoundField DataField="BK_NM" HeaderText="Book Name" />
<asp:BoundField DataField="ATHR_NM" HeaderText="Author Name" />
<asp:BoundField DataField="BUY_YR" HeaderText="Buy Year" />
<asp:BoundField DataField="PRICE" HeaderText="Price" />
</Columns>
Now here, as you can see, there is a HeaderText property which will override the table column name and display the text that is mentioned in here.
You have a couple of options here that you can try :
First, if you want all columns like this with custom header text, you can define all the other columns with these 4 in the same manner as well. That will display all the data and column headers as per the given format.Something like this :
<asp:GridView ID="gdvMyBooks" AutoGenerateColumns="False" runat="server">
<Columns>
<asp:BoundField DataField="BK_NM" HeaderText="Book Name" />
<asp:BoundField DataField="ATHR_NM" HeaderText="Author Name" />
<asp:BoundField DataField="BUY_YR" HeaderText="Buy Year" />
<asp:BoundField DataField="PRICE" HeaderText="Price" />
//other columns using same syntax as above.
</Columns>
</asp:GridView>
Also, if you dont want to bind all columns coming in your query, you can use this attibute in your gridview,
AutoGenerateColumns = False
And just specify the columns that you need like you have currently done.
The other thing is, if you want to straight away bind the result in your query to your GridView, then just remove those 4 BoundField statements and leave as it is. This will bind your table to GridView with the same header names as the column names.
I hope this makes things clear.
You have to set your GridView.AutoGenerateColumns to false :
<asp:GridView ID="gdvMyBooks" runat="server" AutoGenerateColumns="False">
Otherwise, it will bind all the field of your object.

Is it possible to change gridviewid to to a gridview DataSouce after the gridview is loaded

Is it possible to change a gridviews DataSouceId to a gridview DataSouce after the gridview is loaded. I have a gridview with a DataSouceId that is equal to SqlDatasource. I have a button when pressed executes a some LINQ which I want to change what's in the gridview.
var sce = from pk in db.Tables
where pk.Score > 20
select new { pk.First_Name, pk.Last_Name, pk.Score };
GridView1.DataSourceID = "";
GridView1.DataSource = sce;
GridView1.DataBind();
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="First Name" DataSourceID="SqlDataSource2" AllowSorting="True">
<Columns>
<asp:BoundField DataField="First Name" HeaderText="First Name" ReadOnly="True" SortExpression="First Name" />
<asp:BoundField DataField="Last Name" HeaderText="Last Name" SortExpression="Last Name" />
<asp:BoundField DataField="Score" HeaderText="Score" SortExpression="Score" />
<asp:BoundField DataField="Nationality" HeaderText="Nationality" SortExpression="Nationality" />
</Columns>
</asp:GridView>
I tried to change to a empty string. This compiles but crashes when the button is clicked.
Is what I'm trying possible?
The problem is that the query defines columns with different names from what the GridView expects. For example, compare:
pk.First_Name
and
DataField="First Name"
These are different, theerefore GridView is not able to find the column in data source and throws exception.
The best option would be to use underscore in GridView as well. That might require some refactoring in your initial SQL, but it should e done anyway - having spaces in column names is very brittle and uncommon, better refrain from it altogether:
<asp:BoundField DataField="First_Name" ...
Or you can define a TemplateField that looks for column with either name and displays what was found. But that sounds like a terribly huge overhead.

Asp.net/c# -> Gridview Pager doesn't get updated when gridview rows are filtered (or hidden)

I have the below code where I have some conditions because of which I have to hide the row from showing to end user. "ShowRow" is a boolean value that gets set in GetUnitOfMeasure function (not copied here) based on these conditions.
There are some real conditions which is forcing me to hide. I tried to include them while building data source but I have to hide it before display.
Problem I am facing is the paging is not getting refreshed based on total rows shown at the end. For example, if I have TOTAL of 200Rows in the grid and only 2 rows needs to be shown and if these 2 rows are found in paging 3, then when page is loaded it still shows paging 1 2 3 4 and 3rd page has the valid 2 rows.
Please suggest.I have also used "onDataBound" against gridview (not copied here) but I just hide some columns here.
ASPX page
<asp:GridView ID="SearchResults" runat="Server" AutoGenerateColumns="false" EnableViewState="false"
AllowPaging="true" PageSize="50" OnDataBound ="SearchResults_DataBound" OnRowDataBound="SearchResults_RowDataBound">
<RowStyle CssClass="EvenRow" />
<AlternatingRowStyle CssClass="OddRow" />
<Columns>
<asp:TemplateField meta:resourceKey="UmSellField">
<ItemStyle CssClass="alpha" />
<HeaderStyle CssClass="alpha" />
<ItemTemplate>
<asp:Label ID="UmSellLabel" runat="server" EnableViewState="false" Text='<%# GetUnitOfMeasure(Container.DataItem,false) %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
codebehind
protected void SearchResults_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType.Equals(DataControlRowType.DataRow))
{
e.Row.Visible = showRow;
e.Row.Cells[0].Visible = showRow;
}
}

Form Re-Submission Deletes Next GridView Row

I have a Gridview and the OnRowDeleting method with removes a record from the database and the gridview.
My problem is that when a user click the delete button in the Gridview the record will be removed from the database but the GridView does not show this update (does not refresh). If the user then refreshes the page causing a form re-submission then the GridView deletes the row below the originally deleted row and so on if the page is refreshed again.
How can I prevent this from happening?
Here is my gridview:
<asp:GridView runat="server" ID="gvShowQuestionnaires" HeaderStyle-CssClass="table_header" CssClass="view" AlternatingRowStyle-CssClass="alt" AlternatingRowStyle-BackColor="#f3f4f8" AutoGenerateColumns="False"
DataKeyNames='QuestionnaireID' OnRowDeleting="gvShowQuestionnaires_RowDeleting" OnRowEditing="gvShowQuestionnaires_RowEdit" OnSelectedIndexChanged="gvShowQuestionnaires_SelectedIndexChanged" FooterStyle-CssClass="view_table_footer" >
<Columns>
<asp:BoundField DataField="QuestionnaireID" HeaderText="ID" HeaderStyle-Width="80px" ItemStyle-CssClass="bo"></asp:BoundField>
<asp:BoundField DataField="QuestionnaireName" HeaderText="Questionnaire Name" />
<asp:ButtonField CommandName="select" ButtonType="Link" Text="hello" />
<asp:CommandField HeaderText="Options" CausesValidation="true" ShowDeleteButton="True" ShowEditButton="true" EditText="Edit">
</asp:CommandField>
</Columns>
</asp:GridView>
Here is the OnRowDeleting method.
protected void gvShowQuestionnaires_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
int questionnaireID = (int)gvShowQuestionnaires.DataKeys[Convert.ToInt32(e.RowIndex)].Value;
GetData.DeleteQuestionnaire(questionnaireID); // Deletes Questionniare from database
gvShowQuestionnaires.DataSource = DT;
gvShowQuestionnaires.DataBind();
}
You could always redirect the user to the initial page after the row was deleted, e.g. in the RowDeleted handler.
Response.Redirect(Request.RawUrl);
This should work because the delete action is a POST command to the current .aspx page.

Categories