ASP.Net 4.5 Sorting Model Bindings by Navigation Properties

Everything,

I have a grid that has the following columns. Paging works fine, but it doesn't sort. Each time I click on the Category column to sort by category, I would get this error:

The instance property 'Category.CategoryName' is not defined for type 'ESA.Data.Models.Entity.Project'

This error statement is incorrect because gridview was able to correctly display the column.

Here is the select method

public IQueryable<Project> getProjects() { ApplicationServices objServices = new ApplicationServices(); IQueryable<Project> lstProject; lstProject = objServices.getProjects(); return lstProject; } 

Any suggestion?

  <asp:GridView ID="grdProject" runat="server" ShowHeader="true" AutoGenerateColumns="false" CellPadding="2" CellSpacing="2" ItemType="ESA.Data.Models.Entity.Project" SelectMethod="getProjects" DataKeyNames="ProjectID" AllowSorting="true" AllowPaging="true" PageSize="5"> <Columns> <asp:BoundField DataField="ProjectID" HeaderText="ID " ItemStyle-Width="10" /> <asp:BoundField DataField="Category.CategoryName" HeaderText="Category" SortExpression="Category.CategoryName" /> <asp:BoundField DataField="ProjectName" HeaderText="Project Name" ItemStyle-Width="300" /> <asp:BoundField DataField="Status.StatusName" HeaderText="Status" SortExpression="Status.StatusName" /> <asp:BoundField DataField="AddedByUser.UserName" HeaderText="Added By" ItemStyle-Width="120" /> <asp:BoundField DataField="AddedDate" HeaderText="Added Date" ItemStyle-Width="90" DataFormatString="{0:d}" /> </Columns> </asp:GridView> 
+4
source share
3 answers

I had a similar problem with a Listview control. I decided it like that.

first, I use the code from this post Marc Gravell Dynamic LINQ OrderBy on IEnumerable <T>

in my ListView 'OnSorting' event, I added the following code.

 protected void lv_Sorting(object sender, ListViewSortEventArgs e) { e.Cancel = true; ViewState["OrderBy"] = e.SortExpression; lvList.DataBind(); } 

I added a pretty standard way to grab the sortidirection this list.

 public SortDirection sortDirection { get { if (ViewState["sortdirection"] == null) { ViewState["sortdirection"] = SortDirection.Ascending; return SortDirection.Ascending; } else if ((SortDirection)ViewState["sortdirection"] == SortDirection.Ascending) { ViewState["sortdirection"] = SortDirection.Descending; return SortDirection.Descending; } else { ViewState["sortdirection"] = SortDirection.Ascending; return SortDirection.Ascending; } } set { ViewState["sortdirection"] = value; } } 

In my Listview, the Selectmethod looks like this (using the extension method from Marc)

 public IQueryable<SomeObject> GetObjects([ViewState("OrderBy")]String OrderBy = null) { var list = GETSOMEOBJECTS(); if (OrderBy != null) { switch (sortDirection) { case SortDirection.Ascending: list = list.OrderByDescending(OrderBy); break; case SortDirection.Descending: list = list.OrderBy(OrderBy); break; default: list = list.OrderByDescending(OrderBy); break; } } return list; } 

I have not tried it with GridView, but I am sure that it will work the same.

EDIT The following is an example linq extension class that should work

 public static class LinqExtensions { public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property) { return ApplyOrder<T>(source, property, "OrderBy"); } public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property) { return ApplyOrder<T>(source, property, "OrderByDescending"); } public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property) { return ApplyOrder<T>(source, property, "ThenBy"); } public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property) { return ApplyOrder<T>(source, property, "ThenByDescending"); } static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName) { string[] props = property.Split('.'); Type type = typeof(T); ParameterExpression arg = Expression.Parameter(type, "x"); Expression expr = arg; foreach (string prop in props) { // use reflection (not ComponentModel) to mirror LINQ PropertyInfo pi = type.GetProperty(prop); expr = Expression.Property(expr, pi); type = pi.PropertyType; } Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type); LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg); object result = typeof(Queryable).GetMethods().Single( method => method.Name == methodName && method.IsGenericMethodDefinition && method.GetGenericArguments().Length == 2 && method.GetParameters().Length == 2) .MakeGenericMethod(typeof(T), type) .Invoke(null, new object[] { source, lambda }); return (IOrderedQueryable<T>)result; } } 

Just add "anynamespaceyouused" to the page and you should be good to go.

+4
source

Add a string parameter named sortByExpression to your getProjects() method.

If gridView finds this parameter in your method signature, it will not try to "automatically arrange" your result, and it will allow you to complete the task.

To do this yourself, you can use DynamicLinq (you can add the nuget package or use the LinqExtensions class sent by Drauka ).

So your method will look like this:

 // using System.Linq.Dynamic; public IQueryable<Project> getProjects(string sortByExpression) { ApplicationServices objServices = new ApplicationServices(); IQueryable<Project> lstProject = objServices.getProjects(); if (!String.IsNullOrEmpty(sortByExpression)) lstProject = lstProject.OrderBy(sortByExpression); return lstProject; } 

This way you won't get around gridView sorting styles.

Source: decompiled framework code, especially System.Web.UI.WebControls.ModelDataSourceView.IsAutoSortingRequired(...)

+2
source

Drauka your solution works for me, but I would get an error on this line of code, although I already refer to System.Linq.Dynamic

Two lines that give me a syntax error:

lstProject = lstProject.OrderByDescending (OrderBy);

and error message

Type arguments to the method "System.Linq.Enumerable.OrderByDescending (System.Collections.Generic.IEnumerable, System.Func)" cannot be taken out of use. Try explicitly specifying type arguments.

  public IQueryable<Project> getProjects([ViewState("OrderBy")]String OrderBy = null) { ApplicationServices objServices = new ApplicationServices(); var lstProject = objServices.getProjects(); if (OrderBy != null) { switch (sortDirection) { case SortDirection.Ascending: lstProject = lstProject.OrderByDescending(OrderBy); break; case SortDirection.Descending: lstProject = lstProject.OrderBy(OrderBy); break; default: lstProject = lstProject.OrderByDescending(OrderBy); break; } } return lstProject; } 
0
source

Source: https://habr.com/ru/post/1480781/


All Articles