如何在 linq 中使用自定义列值对列表进行排序?
How to sort List using custom column values in linq?
Net 核心、Ef 核心和 linq。我有 table 列状态。它包含值 New、In-Progress 和 closed。当我查询所有带有 New 的行时,应该首先出现,然后是进行中和关闭。下面是我的代码。
var Requests = await this.RequestRepository.GetAsync(x => x.IsActive == true && x.CreatedBy == LoggedInUser, null, x => x.Country).ConfigureAwait(false);
下面是我的 GetAsync 方法
public async Task<IEnumerable<T>> GetAsync(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, params Expression<Func<T, object>>[] includes)
{
IQueryable<T> query = this.dbSet;
foreach (Expression<Func<T, object>> include in includes)
{
query = query.Include(include);
}
if (filter != null)
{
query = query.Where(filter);
}
if (orderBy != null)
{
query = orderBy(query);
}
return await query.ToListAsync().ConfigureAwait(false);
}
所以我希望所有状态为 New 的行应该先出现,然后是 In-Progress 并关闭。无论如何我都找不到弄清楚。有人可以帮我写这个吗。任何帮助,将不胜感激。谢谢
我已经按照您的要求制作了示例代码。它在我身上运行良好。请参考这个。希望这也适用于您的代码。
using System;
using System.Collections.Generic;
using System.Linq;
namespace Test
{
public class Program
{
public static void Main(string[] args)
{
List<Name> list = new List<Name>
{
new Name { FirstName = "Nishan1", LastName = "Dhungana1", Status = Status.Closed},
new Name { FirstName = "Nishan2", LastName = "Dhungana2", Status = Status.New},
new Name { FirstName = "Nishan3", LastName = "Dhungana3", Status = Status.New},
new Name { FirstName = "Nishan4", LastName = "Dhungana4", Status = Status.Closed},
new Name { FirstName = "Nishan5", LastName = "Dhungana5", Status = Status.Closed},
new Name { FirstName = "Nishan6", LastName = "Dhungana6", Status = Status.InProgress},
new Name { FirstName = "Nishan7", LastName = "Dhungana7", Status = Status.Closed},
new Name { FirstName = "Nishan8", LastName = "Dhungana8", Status = Status.InProgress},
new Name { FirstName = "Nishan9", LastName = "Dhungana9", Status = Status.InProgress},
new Name { FirstName = "Nishan10", LastName = "Dhungana10", Status = Status.New},
new Name { FirstName = "Nishan11", LastName = "Dhungana11", Status = Status.New}
};
list = list.OrderByDescending(x => x.Status == Status.New)
.ThenByDescending(x => x.Status == Status.InProgress)
.ThenByDescending(x => x.Status == Status.Closed)
.ToList();
Console.WriteLine("hey");
Console.ReadLine();
}
}
public class Name
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Status Status { get; set; }
}
public enum Status
{
New = 1,
InProgress = 2,
Closed = 3
}
}
如果您抛弃这个“辅助”方法而直接使用 LINQ,您的生活可能会轻松很多。看看它的可读性有多明显:
var apps = db.FundingApplications
.Include(x => x.Applicant)
.Where(x => x.ApplicationDate.Year == DateTime.Now.Year)
.OrderBy(x => (int)x.Status)
(为了简洁,我跳过了 await/async,并不是因为我提倡同步)
状态当然是枚举,如:
enum Status{
New, Inprogress, Closed
}
如果你的枚举不是像这样的数字顺序而是 eg
enum Status {
New = 20,
InProgress = 1,
Closed = 99
}
然后您可以在 ToString 之后通过降序对其进行排序(您会注意到名称的字母顺序相反)或使用映射例如 d[New] = 0, d[InProgress] = 1 ...
的字典创建映射,或者执行(在-line) 如果在 OrderBy 中设置。
OrderByDescending(x => x.Status.ToString("g"));
var d = new Dictionary<status, int>() {
{New, 0}, {InProg,1}, {Closed,2}
};
OrderBy(x => d[x.Status]);
OrderBy(x => x.Status == Status.New ? 0 : (x.Status == Status.InProg ? 1 : 2))
不过只有最后一个有真正的机会在服务器上执行,并且只有在您不重命名它们或添加破坏顺序的新名称时,按名称排序才有效。
我也很欣赏另一个答案中给出的 OrderBy/ThenBy 并认为它很好,但我认为应该注意测试它是在服务器上还是在客户端上执行,因为它执行布尔比较和许多数据库不使用布尔值作为数据类型,或者如果他们这样做,他们可能会在 true (1)
之前排序 falsy (0)
OrderBy(x => x.Status == New)
可能就是这样,它将所有已关闭的和 InProg 排在 New 之前,因为如果服务器评估的布尔值的结果是 InProg/closed 的 0 和 new 的 1。 MySql 和 Postgres 将是我的首选,因为我担心这会被服务器评估,因为它们确实允许在其他数据库不允许的上下文中使用布尔类型值。
因此,请注意 a) 这种排序正在评估您期望和想要的位置 (client/server) 和 b) 如果它确实在服务器上评估,那么服务器会按照您的需要进行排序
编辑,刚刚看到您的评论表明 Status 不是枚举而是一组字符串常量??
如果您的数据库值实际上是字符串并且状态从来都不是枚举,那么您可以按降序排列它们
OrderByDescending(x => x.Status)
Net 核心、Ef 核心和 linq。我有 table 列状态。它包含值 New、In-Progress 和 closed。当我查询所有带有 New 的行时,应该首先出现,然后是进行中和关闭。下面是我的代码。
var Requests = await this.RequestRepository.GetAsync(x => x.IsActive == true && x.CreatedBy == LoggedInUser, null, x => x.Country).ConfigureAwait(false);
下面是我的 GetAsync 方法
public async Task<IEnumerable<T>> GetAsync(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, params Expression<Func<T, object>>[] includes)
{
IQueryable<T> query = this.dbSet;
foreach (Expression<Func<T, object>> include in includes)
{
query = query.Include(include);
}
if (filter != null)
{
query = query.Where(filter);
}
if (orderBy != null)
{
query = orderBy(query);
}
return await query.ToListAsync().ConfigureAwait(false);
}
所以我希望所有状态为 New 的行应该先出现,然后是 In-Progress 并关闭。无论如何我都找不到弄清楚。有人可以帮我写这个吗。任何帮助,将不胜感激。谢谢
我已经按照您的要求制作了示例代码。它在我身上运行良好。请参考这个。希望这也适用于您的代码。
using System;
using System.Collections.Generic;
using System.Linq;
namespace Test
{
public class Program
{
public static void Main(string[] args)
{
List<Name> list = new List<Name>
{
new Name { FirstName = "Nishan1", LastName = "Dhungana1", Status = Status.Closed},
new Name { FirstName = "Nishan2", LastName = "Dhungana2", Status = Status.New},
new Name { FirstName = "Nishan3", LastName = "Dhungana3", Status = Status.New},
new Name { FirstName = "Nishan4", LastName = "Dhungana4", Status = Status.Closed},
new Name { FirstName = "Nishan5", LastName = "Dhungana5", Status = Status.Closed},
new Name { FirstName = "Nishan6", LastName = "Dhungana6", Status = Status.InProgress},
new Name { FirstName = "Nishan7", LastName = "Dhungana7", Status = Status.Closed},
new Name { FirstName = "Nishan8", LastName = "Dhungana8", Status = Status.InProgress},
new Name { FirstName = "Nishan9", LastName = "Dhungana9", Status = Status.InProgress},
new Name { FirstName = "Nishan10", LastName = "Dhungana10", Status = Status.New},
new Name { FirstName = "Nishan11", LastName = "Dhungana11", Status = Status.New}
};
list = list.OrderByDescending(x => x.Status == Status.New)
.ThenByDescending(x => x.Status == Status.InProgress)
.ThenByDescending(x => x.Status == Status.Closed)
.ToList();
Console.WriteLine("hey");
Console.ReadLine();
}
}
public class Name
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Status Status { get; set; }
}
public enum Status
{
New = 1,
InProgress = 2,
Closed = 3
}
}
如果您抛弃这个“辅助”方法而直接使用 LINQ,您的生活可能会轻松很多。看看它的可读性有多明显:
var apps = db.FundingApplications
.Include(x => x.Applicant)
.Where(x => x.ApplicationDate.Year == DateTime.Now.Year)
.OrderBy(x => (int)x.Status)
(为了简洁,我跳过了 await/async,并不是因为我提倡同步)
状态当然是枚举,如:
enum Status{
New, Inprogress, Closed
}
如果你的枚举不是像这样的数字顺序而是 eg
enum Status {
New = 20,
InProgress = 1,
Closed = 99
}
然后您可以在 ToString 之后通过降序对其进行排序(您会注意到名称的字母顺序相反)或使用映射例如 d[New] = 0, d[InProgress] = 1 ...
的字典创建映射,或者执行(在-line) 如果在 OrderBy 中设置。
OrderByDescending(x => x.Status.ToString("g"));
var d = new Dictionary<status, int>() {
{New, 0}, {InProg,1}, {Closed,2}
};
OrderBy(x => d[x.Status]);
OrderBy(x => x.Status == Status.New ? 0 : (x.Status == Status.InProg ? 1 : 2))
不过只有最后一个有真正的机会在服务器上执行,并且只有在您不重命名它们或添加破坏顺序的新名称时,按名称排序才有效。
我也很欣赏另一个答案中给出的 OrderBy/ThenBy 并认为它很好,但我认为应该注意测试它是在服务器上还是在客户端上执行,因为它执行布尔比较和许多数据库不使用布尔值作为数据类型,或者如果他们这样做,他们可能会在 true (1)
之前排序 falsy (0)OrderBy(x => x.Status == New)
可能就是这样,它将所有已关闭的和 InProg 排在 New 之前,因为如果服务器评估的布尔值的结果是 InProg/closed 的 0 和 new 的 1。 MySql 和 Postgres 将是我的首选,因为我担心这会被服务器评估,因为它们确实允许在其他数据库不允许的上下文中使用布尔类型值。
因此,请注意 a) 这种排序正在评估您期望和想要的位置 (client/server) 和 b) 如果它确实在服务器上评估,那么服务器会按照您的需要进行排序
编辑,刚刚看到您的评论表明 Status 不是枚举而是一组字符串常量??
如果您的数据库值实际上是字符串并且状态从来都不是枚举,那么您可以按降序排列它们
OrderByDescending(x => x.Status)