C#中LinQ条件排序

3

这是我的查询:

 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();

我有一个模型,其中包含布尔值SortTrackSortCategorySortSkills

如果布尔值为true,则按升序排序;如果为false,则按降序排序。

如何实现?


不要使用内联方式,这样很难阅读。 - Tân
@TânNguyễn 我不知道如何将一个Linq查询内联,我通常这样编码是为了更容易阅读代码 :D - user7305885
3个回答

4
在Lambda中,可以像这样完成:
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();

否则,您需要使用这样的表达式:
var x = widgets.Where(w => w.Name.Contains("xyz"));
if (flag) {
  x = x.OrderBy(w => w.property);
} else {
  x = x.OrderByDescending(w => w.property);
}

OrderBy("")仍然会遍历整个列表吗? - Rabid Penguin
@RabidPenguin 我认为不行。这将等同于 OrderBy(x => ""),因此我们没有在任何列上实现此 orderby,它不会迭代。 - Ankit Sahrawat

2

Linq语句是可组合的,所以在调用tolist之前可以向查询中添加适当的orderby。

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

return query.ToList();

你能用那个编辑我的代码吗?因为我尝试过了,但在第三个对象中遇到了问题,它找不到ID。 - user7305885

2
这里有一些更符合LINQ精神的选项。EF将无法将它们翻译成SQL,因此您需要在内存中运行这些选项(在AsEnumerable / ToArray / ToList之后),但看起来这不会是一个问题。
以这个简单的例子为例:
var numbers = new int[] { 5, 1, 2, 3, 44 };

选项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);
    }
}

使用方法

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);
    }
}

用法

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);

选项三

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);
    }
}

使用方法

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);

从生产角度来看,我可能会创建一个SortDirection枚举类型,其中包含AscendingDescending值,而不是命名为asc的布尔变量,但我就是这么傻。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接