How to Conditionally the column in LINQ OrderByDescending for OrderBy in C#?

.net c# dynamic-linq entity-framework linq

Question

How to utilize the LINQ OrderBy Clause to conditionally sort the column.

example: I Own a PropertyFilter.OrderBy and Filter.Order . InOrderBy numerous things, such as Name, Address, City, etc.Order I'm not sure how to sort it using conditional columns since it will either be ascending or descending.

Please use the code below as a guide.

IQueryable<Filter> query;

PropertyInfo prop = typeof(Filter).GetProperty(Filter.OrderBy);  

if (Filter.Order ==" Ascending"){
  query = query.OrderBy ( x = > prop.GetValue(x,null));
}
else if (Filter.Order ==" Descending"){
  query = query.OrderByDescending ( x = > prop.GetValue(x,null));
}

But query is failing . I'm not sure what the problem is. I can see that the expression prop uses reflection, but not the prop property. GetValue does not function.

Please assist me with this.

1
0
3/26/2020 9:40:29 PM

Accepted Answer

You may utilize the dynamic querying, selecting, and sorting supported System.Linq.Dynamic.Core library.

Sample of a code

var q = new List<Person>
{
    new Person{Name = "C", Age = 30 },
    new Person{Name = "A", Age = 7 },
    new Person{Name = "B", Age = 5 }
}.AsQueryable();

var x1 = q.OrderBy("Name asc");

var a1 = q.OrderBy("Age desc");

dotnetfiddle is a functional example in its entirety.

0
3/28/2020 3:38:52 PM

Popular Answer

public static class LinqUtils
    {
        /// <summary>
        /// Orders the by.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="direction">The direction.</param>
        /// <returns></returns>
        public static IOrderedMongoQueryable<T> OrderBy<T>(this IMongoQueryable<T> source, string propertyName, OrderDirection direction)
        {
            switch (direction)
            {
                case OrderDirection.ASC:
                    return source.OrderBy(ToLambda<T>(propertyName));

                case OrderDirection.DESC:
                    return source.OrderByDescending(ToLambda<T>(propertyName));

                default:
                    return source.OrderBy(ToLambda<T>(propertyName));
            }

        }

        /// <summary>
        /// Orders the by.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="direction">The direction.</param>
        /// <returns></returns>
        public static IOrderedMongoQueryable<T> OrderBy<T>(this IMongoQueryable<T> source, string propertyName, int direction)
        {
            var dir = (OrderDirection)direction;

            switch (dir)
            {
                case OrderDirection.ASC:
                    return source.OrderBy(ToLambda<T>(propertyName));

                case OrderDirection.DESC:
                    return source.OrderByDescending(ToLambda<T>(propertyName));

                default:
                    return source.OrderBy(ToLambda<T>(propertyName));
            }

        }


        /// <summary>
        /// Orders the by.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <returns></returns>
        public static IOrderedMongoQueryable<T> OrderBy<T>(this IMongoQueryable<T> source, string propertyName)
        {
            return source.OrderBy(ToLambda<T>(propertyName));
        }

        /// <summary>
        /// Orders the by descending.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <returns></returns>
        public static IOrderedMongoQueryable<T> OrderByDescending<T>(this IMongoQueryable<T> source, string propertyName)
        {
            return source.OrderByDescending(ToLambda<T>(propertyName));
        }

        /// <summary>
        /// Wheres the specified property name.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="stringToSource">The string to source.</param>
        /// <returns></returns>
        public static IMongoQueryable<T> Where<T>(this IMongoQueryable<T> source, string propertyName, string stringToSource)
        {
            return source.Where(ToLambdaWhere<T>(propertyName, stringToSource));
        }


        /// <summary>
        /// Wheres the text.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query">The query.</param>
        /// <param name="field">The field.</param>
        /// <param name="search">The search.</param>
        /// <returns></returns>
        public static IMongoQueryable<T> WhereText<T>(this IMongoQueryable<T> query, Expression<Func<T, object>> field, string search)
        {

            search = Regex.Escape(search);
            var filter = Builders<T>.Filter.Text(search);
            var member = HelpersLinq.PropertyName<T>(field);

            var regexFilter = string.Format("^{0}.*", search);
            var filterRegex = Builders<T>.Filter.Regex(member, BsonRegularExpression.Create(new Regex(regexFilter, RegexOptions.IgnoreCase)));

            return query.Where(_ => filter.Inject() && filterRegex.Inject());
        }

        /// <summary>
        /// Converts to lambda.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="propertyName">Name of the property.</param>
        /// <returns></returns>
        private static Expression<Func<T, object>> ToLambda<T>(string propertyName)
        {
            var parameter = Expression.Parameter(typeof(T));
            var property = Expression.Property(parameter, propertyName);
            var propAsObject = Expression.Convert(property, typeof(object));

            return Expression.Lambda<Func<T, object>>(propAsObject, parameter);
        }

        /// <summary>
        /// Converts to lambdawhere.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="stringToSearch">The string to search.</param>
        /// <returns></returns>
        private static Expression<Func<T, bool>> ToLambdaWhere<T>(string propertyName, string stringToSearch)
        {
            //var parameter = Expression.Parameter(typeof(T));

            // Create a parameter to use for both of the expression bodies.
            var parameter = Expression.Parameter(typeof(T), "x");
            // Invoke each expression with the new parameter, and combine the expression bodies with OR.
            var predicate = Expression.Lambda<Func<T, bool>>(Expression.Call(Expression.PropertyOrField(parameter, propertyName), "Contains", null, Expression.Constant(stringToSearch)), parameter);

            return predicate;
        }
    }


    public static class HelpersLinq
    {
        public static string PropertyName<T>(Expression<Func<T, object>> expression)
        {
            var member = expression.Body as MemberExpression;
            if (member != null && member.Member is PropertyInfo)
                return member.Member.Name;

            throw new ArgumentException("Expression is not a Property", "expression");
        }
    }

public enum OrderDirection
{
    ASC = 1,
    DESC
}

So you may use it like this:

 initialQuery.OrderBy("Name", OrderDirection.ASC)

Hope it's useful to you!



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow