简体   繁体   中英

C# LinQ Conditional OrderBy

so this is my query

 var results = tcs.Skip(searchModel.PageSize * (searchModel.Page - 1))
                .Take(searchModel.PageSize)
                .AsEnumerable()
                .Select(x => new
                {
                    trackId = x.TrackId,
                    trackName = x.TrackName,
                    category = _weCategoryService.FindAll().Where(y => y.WorkExperience_Track.TrackId == x.TrackId)
                        .Select(y => new {
                            categoryId = y.CategoryId,
                            categoryName = y.CategoryName,
                            skill = _skillsService.FindAll().Where(z => z.CategoryId == y.CategoryId)
                                .Select(z => new {
                                    skillId = z.SkillId,
                                    skillName = z.SkillName
                                }).OrderBy(z => z.skillName).ToList()
                        }).OrderBy(y => y.categoryName).ToList()
                }).OrderBy(x => x.trackName).ToList();

Then i have a model which has a boolean value for SortTrack , SortCategory and SortSkills . I want to OrderBy Ascending if the value of the boolean is true and Descending if false.

How to achieve that?

Linq statements are composable so you can add the appropriate orderby to the query before calling tolist.

var query = list.Where(...)
if (condition)
    query = query.OrderBy(...)
else
    query = query.OrderByDescending(...)

return query.ToList();

In lambda it can be done like this:

var results = tcs.Skip(searchModel.PageSize * (searchModel.Page - 1))
                    .Take(searchModel.PageSize)
                    .AsEnumerable()
                    .Select(x => new
                    {
                        trackId = x.TrackId,
                        trackName = x.TrackName,
                        category = _weCategoryService.FindAll().Where(y => y.WorkExperience_Track.TrackId == x.TrackId)
                            .Select(y => new {
                                categoryId = y.CategoryId,
                                categoryName = y.CategoryName,
                                skill = _skillsService.FindAll().Where(z => z.CategoryId == y.CategoryId)
                                    .Select(z => new {
                                        skillId = z.SkillId,
                                        skillName = z.SkillName
                                    }).OrderBy(z => SortSkills ? z.skillName : "").OrderByDescending(z => !SortSkills ? z.skillName : "").ToList()
                            }).OrderBy(y => SortCategory ? y.categoryName : "").OrderByDescending(y => !SortCategory ? y.categoryName : "").ToList()
                    }).OrderBy(x => SortTrack ? x.trackName : "").OrderByDescending(x => !SortTrack ? x.trackName : "").ToList();

Else you need to use expressions like this:

var x = widgets.Where(w => w.Name.Contains("xyz"));
if (flag) {
  x = x.OrderBy(w => w.property);
} else {
  x = x.OrderByDescending(w => w.property);
}

Here are a few other options more in the LINQ spirit. EF won't be able to translate them to SQL, so you'll need to run these in-memory (post-AsEnumerable/ToArray/ToList) but it looks like it won't be a problem.

Take this as a simple example:

var numbers = new int[] { 5, 1, 2, 3, 44 };

Option 1

public static class EnumerableExtensions
{
    public static IOrderedEnumerable<T> OrderByAdaptive<T, TKey>(
        this IEnumerable<T> enumr, 
        Func<T, TKey> selector, 
        bool ascending
    )
    {
        return ascending
            ? enumr.OrderBy(selector)
            : enumr.OrderByDescending(selector);
    }

    public static IOrderedEnumerable<T> OrderByAdaptive<T, TKey>(
        this IEnumerable<T> enumr, 
        Func<T, TKey> selector, 
        IComparer<TKey> comparer, 
        bool ascending
    )
    {
        return ascending
            ? enumr.OrderBy(selector, comparer)
            : enumr.OrderByDescending(selector, comparer);
    }
}

Usage

var asc = true; // or false
var sorted = numbers.OrderByAdaptive(x => x, asc);

Option 2

public class LambdaComparer<T> : IComparer<T>
{
    private Func<T, T, int> _cmp;

    public LambdaComparer(Func<T, T, int> cmp)
    {
        _cmp = cmp;
    }

    public int Compare(T x, T y)
    {
        return _cmp(x, y);
    }
}

Usage

var ascComparer = new LambdaComparer<int>((x, y) => { 
    if (x > y) return 1; 
    else if (x < y) return -1; 
    else return 0; 
});

var descComparer = new LambdaComparer<int>((x, y) => { 
    if (x > y) return -1; // Note the sign change
    else if (x < y) return 1; // Note the sign change
    else return 0; 
});

var asc = true; // or false

var sorted = numbers.OrderBy(x => x, asc ? ascComparer : descComparer);

Option 3

public class ReverseComparer<T> : IComparer<T> where T : IComparable<T>
{
    private IComparer<T> _nonReversed;

    public ReverseComparer()
    {
        _nonReversed = Comparer<T>.Default;
    }

    public ReverseComparer(IComparer<T> nonReversed)
    {
        _nonReversed = nonReversed;
    }

    public int Compare(T obj1, T obj2)
    {
        return -1 * _nonReversed.Compare(obj1, obj2);
    }
}

Usage

var ascComparer = Comparer<int>.Default;
var descComparer = new ReverseComparer<int>(); // or new ReverseComparer<int>(ascComparer);

var asc = true; // or false

var sorted = numbers.OrderBy(x => x, asc ? ascComparer : descComparer);

Production-wise, I would probably create a SortDirection enum with Ascending and Descending values rather than a bool named asc , but I'm silly like that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM