参考资料《ASP.NET Core与RESTful API开发实战》作者:杨万青
排序跟搜索、过滤一样,需要在传入的uri里用QueryString来传入参数,例如:
https://localhost:5001/api/posts?pageNumber=0
问号后面就是QueryString。
常规方式
大致可以这样实现,创建一个xxParameters类,里面定义QueryString的属性。我们假设我们有一个Post模型,在数据库中保存着Post数据(这个Post的意思是帖子,不是HttpPost),其中Post有一个属性是Title,我们可以定义Post的Parameters类:
public class PostParameters
{
...
public string SortBy { get; set; } = "Title"
}
上述代码顺便为SortBy设置了默认值,按Post模型的Title属性排序。
Post对应着一个仓储类PostReposiyoty,仓储类中实现了查询Post数据的方法,其中有一个GetAllAsync方法可以查询出所有的数据。我们给这个方法传入PostParameters类的参数,并且调用其中的SortBy属性,使用OrderBy子句实现查询:
public Task<PagedList<Post>> GetAllAsync(PostParameters postParameters)
{
IQueryable<Post> queryablePosts = DbContext.Set<Post>();
...
if(parameters.SortBy == "Title")
{
queryablePosts = queryblePosts.OrderBy(post => post.Title);
}
...
}
使用第三方库的简易方式
Linq的OrderBy方法不可以直接使用字符串,如:OrderBy("Title")
进行排序,如果我们想要后续支持根据多个属性排序的话,要写无数个这种if语句,太麻烦。我从《ASP.NET Core与RESTful API开发实战》这本书中发现可以使用System.Linq.Dynamic.Core这个库实现动态Linq查询。支持直接使用属性名和多属性(用逗号隔开)进行排序,想要降序排序(跟微博一样,时间晚的靠前),可以在属性名后面加空格再加desc或者descending,升序的话就asc或者ascending。
下面我们来试一下,先安装Microsoft.EntityFrameworkCore.DynamicLinq库:
我们尝试使用Post的创建时间来进行排序,给Post实体模型添加一个属性:
public DateTime CreateTime { get; set; }
在Controller的HttpPost方法里处理新创建的post的时候,可以用:
post.CreateTime = DateTime.Now;
来初始化每一个新创建的post。
然后在PostParameters里把SortBy的默认值改成"CreateTime desc",因为我们要逆序排序。
然后在仓储类PostRepository类的GetAllAsync方法中添加:
public Task<PagedList<Post>> GetAllAsync(PostParameters postParameters)
{
IQueryable<Post> queryablePosts = DbContext.Set<Post>();
...
var orderedPosts = queryablePosts.OrderBy(postParameters.SortBy);
...
}
在这里我们只用了postParameters.SortBy
作为排序的属性,如果用多个,可以用逗号隔开。而且使用OrderBy(...)
的时候会报错,并且没有自动修补,需要我们手动在文件上方using System.Linq.Dynamic.Core;
,这个害得我搞了半个小时才发现是这个问题,对初学者来说太坑了。
同时排序选项也是分页元数据的一部分,别忘了生成分页元数据时返回给客户端。
测试一下:
可以看出创建时间越晚的,排序越靠前。完成。