Friday, April 11, 2014

How to call for a dynamic OrderBy method for a LINQ?

As I wanted to do some experiences in Asp.Mvc 4 I needed a nice way to generate tables using Ajax calls for showing rows, edit, delete and create new item as well with filtering and paging functions
For that I have found this nice package jTable. You could go to http://www.jtable.org/ where you can see a demo by yourself.

Now that I have introduced the scenario I came to an issue. When implementing the sorting of columns by pressing on a column I had as an input parameter string jtSorting which had as a value: "Name ASC", so column name and ordering. Then in my controller's action I had a LINQ query that accessed also the OrderBy extension method which needs exactly the name of property. So I needed a method to order dynamically by property as a string.

Happily I found a solution. Here are my helper classes that I used in final extension method.

public static class OrderHelper
    {
        public class ColumnToSort
        {
            public string ColumnName { get; set; }
            public SortDirection Direction { get; set; }

            public ColumnToSort()
            { }

            public ColumnToSort(string columnName, SortDirection direction)
            {
                ColumnName = columnName;
                Direction = direction;
            }
        }

        public static ColumnToSort SplitJqueryFormatColumn(string sortingColumn) //assume we have as input: "Name ASC"
        {
            ColumnToSort columnToSort = new ColumnToSort();

            if (sortingColumn != null)
            {
                string[] parts = sortingColumn.Split(' ');
                if (parts.Length == 2)
                {
                    columnToSort.ColumnName = parts[0];
                    columnToSort.Direction = parts[1].ToLower() == "asc" ? SortDirection.Ascending : SortDirection.Descending;
                }
            }

            return columnToSort;
        }
    }

This is the extension method that will Order dynamically by a column string value and an sorting order.

public static class OrderExt
    {
        public static IOrderedQueryable< T > Order< T>(this IQueryable< T> source, string propertyName, SortDirection descending, bool anotherLevel = false)
        {
            var param = Expression.Parameter(typeof(T), string.Empty);
            var property = Expression.PropertyOrField(param, propertyName);
            var sort = Expression.Lambda(property, param);

            var call = Expression.Call(
                typeof(Queryable),
                (!anotherLevel ? "OrderBy" : "ThenBy") +
                (descending == SortDirection.Descending ? "Descending" : string.Empty),
                new[] { typeof(T), property.Type },
                source.Expression,
                Expression.Quote(sort));

            return (IOrderedQueryable< T>)source.Provider.CreateQuery< T>(call);
        }
    }

Here is how to use the Order extension method for List Action that is needed for JTable in ASP.NET MVC 4:

[HttpPost]
        public JsonResult List(int jtStartIndex, int jtPageSize, string jtSorting = null)
        {
            try
            {
                int totalItemsNumber = db.Authors.Count();
        
                OrderHelper.ColumnToSort columnToSort = new OrderHelper.ColumnToSort();
                if (jtSorting != null)
                    columnToSort = OrderHelper.SplitJqueryFormatColumn(jtSorting);
                else
                    columnToSort = new OrderHelper.ColumnToSort("Name", SortDirection.Ascending);

                List< author> authors = db.Authors
                                         .Order(columnToSort.ColumnName, columnToSort.Direction)
                                         .Skip(jtStartIndex)
                                         .Take(jtPageSize)
                                         .ToList();

                return Json(new { Result = "OK", Records = authors, TotalRecordCount = totalItemsNumber });
            }
            catch (Exception ex)
            {
                return Json(new { Result = "ERROR", Message = ex.Message });
            }
        }

Hope it solved your issue, too.

Source for the extension method found at: linq-to-entities-dynamic-sorting.

No comments:

Post a Comment