listviewsortingmodel-bindingentity-framework-6commandargument

Sorting a Foreign Key column in a Model Bound Listview


I'm using a Listview to display some data using model binding and I'm trying to sort a column in the listview that relates to a foreign key column in the data source, namely the book column.

The Data Model is as follows:

public class Book 
{
    public Book() {
        this.Factions = new HashSet<Faction>();
    }

    public int Id { get; set; }
    [Required]
    [MaxLength(50)]
    public string Title { get; set; }

   public virtual ICollection<Faction> Factions { get; set; }
}

public class Faction 
{    
    public int Id { get; set; }
    [Required]
    [MaxLength(50)]
    public string Name { get; set; }
    [MaxLength(10)]
    public string Abbreviation { get; set; }

    public int? BookId { get; set; }
    public virtual Book Book { get; set; }
}

And this is the HTML to display the headings for the ListItem

<asp:ListView ID="FactionListView" runat="server"
ItemType="DCW.Models.Faction" DataKeyNames="Id"
SelectMethod="FactionGetData"
<LayoutTemplate>
    <table class="table table-hover table-bordered">
        <thead>
            <tr>
               <th>
                    <asp:LinkButton ID="FactionListViewName" runat="server" CommandName="Sort"
                        CommandArgument="Name">Name</asp:LinkButton></th>
                <th>
                    <asp:LinkButton ID="FactionListViewAbbreviation" runat="server" CommandName="Sort"
                        CommandArgument="Abbreviation">Abbreviation</asp:LinkButton></th>
                <th>
                    <asp:LinkButton ID="FactionListViewBook" runat="server" CommandName="Sort"
                        CommandArgument="Book">Book</asp:LinkButton></th>
            </tr>
        </thead>
        <tbody>
            <asp:PlaceHolder ID="itemPlaceholder" runat="server" />
        </tbody>
    </table>
</LayoutTemplate>

When clicking on the Book LinkButton I get the error: Sys.WebForms.PageRequestManagerServerErrorException: DbSortClause expressions must have a type that is order comparable.

If I change the Linkbutton CommandArgument to either Book.Id or it.Book.Title (which I had read on some other posts might work) then I get the error: Sys.WebForms.PageRequestManagerServerErrorException: Exception has been thrown by the target of an invocation.

So how do I sort a related column of a Model Bound Listview?

Thanks.


Solution

  • So it seems that Model Binding doesn't handle sorting Navigation Properties (Foreign Keys) out of the box. I found the following which is what I used to solve this problem: ASP.Net 4.5 Model Binding Sorting By Navigation Property

    So this:

    <asp:LinkButton ID="FactionListViewBook" runat="server" CommandName="Sort"
                        CommandArgument="Book">Book</asp:LinkButton></th>
    

    Became:

    <asp:LinkButton ID="FactionListViewBook" runat="server" CommandName="Sort"
                        CommandArgument="Book.Title">Book</asp:LinkButton></th>
    

    And my SelectMethod became:

    public IQueryable<GameFaction> FactionGetData(string sortByExpression)
        {
            IQueryable<Faction> query = _context.Factions.Include(faction => faction.Book);
    
            sortByExpression = sortByExpression == null ? "Name" : sortByExpression;
            if (sortByExpression.EndsWith(" DESC"))
            {
                query = query.OrderByDescending(sortByExpression.SubString(0, sortByExpression.Length - 5));
            }
            else
            {
                query = query.OrderBy(sortByExpression);
            }
    
            return query;
        }
    

    Note that this uses the extension method mentioned in the link above which originally came from here: Dynamic LINQ OrderBy on IEnumerable<T>