asp.net core 排序过滤分页组件:sieve(1)
使用asp.net core开发时避免不了要用一个合适的分页组件来让前端获取分页数据。github上面有一个开源的分页组件在这方面很适合我的使用,于是我把他的文档翻译一下,随后会分析它里面的源码。这是第一篇,介绍它如何使用。
Sieve
Sieves是一个.net core下面的简单、干净并且可扩展的框架,它对外暴露了排序,过滤和分页的功能。
ASP.NET Core下的使用方式
在本例中,考虑一个带有Post实体的应用程序。在获取所有可用的帖子时,我们将使用Sieve添加排序、过滤和分页功能。
1. 添加必要的服务
在StartUp.cs文件中编辑ConfigureService方法,将SieveProcessor服务注入进去:
services.AddScoped<SieveProcessor>();
2. 然后告诉Sieve你要让哪几个属性可以进行排序或过滤
Sieve只会对标记有Sieve Attribute的属性(例如:[Sieve(Cansort=true,CanFilter=true)])进行排序或者过滤,所以,在我们的Post的例子中:
public int Id { get; set; } [Sieve(CanFilter = true, CanSort = true)]
public string Title { get; set; } [Sieve(CanFilter = true, CanSort = true)]
public int LikeCount { get; set; } [Sieve(CanFilter = true, CanSort = true)]
public int CommentCount { get; set; } [Sieve(CanFilter = true, CanSort = true, Name = "created")]
public DateTimeOffset DateCreated { get; set; } = DateTimeOffset.UtcNow;
Name参数可以为客户端提供一个不一样的名字
NOTE:你可以使用Fluent API实现一样的功能,就像EF Core中的Fluent Api(IEntityTypeConfiguration)一样的道理和用法。
3.在Controller中使用SieveModel来获取排序、过滤以及分页查询参数
在下面这个Action中处理返回的Post,使用SieveModel来获取排序过滤以及分页查询参数。同时,将SieveProcessor注入到你的Controller中,只要使用它的Apply<TEntity>方法就可以了:
[HttpGet]
public JsonResult GetPosts(SieveModel sieveModel)
{
var result = _dbContext.Posts.AsNoTracking(); // Makes read-only queries faster
result = _sieveProcessor.Apply(sieveModel, result); // Returns `result` after applying the sort/filter/page query in `SieveModel` to it
return Json(result.ToList());
}
你也可以通过应用这个方法中的可选参数来显式的指定你的意图,比如你只想要过滤或者配许,或者分页。具体查看它的Api吧。
4.发送一个请求
GET /GetPosts
?sorts= LikeCount,CommentCount,-created // sort by likes, then comments, then descendingly by date created
&filters= LikeCount>10, Title@=awesome title, // filter to posts with more than 10 likes, and a title that contains the phrase "awesome title"
&page= 1 // get the first page...
&pageSize= 10 // ...which contains 10 posts
添加自定义的排序/过滤方法
如果你想要添加自定义的排序和过滤方法,注入ISieveCustomSortMethods
或ISieveCustomFilterMethods
这两个接口的实现就可以了,Sieve会查询到你注入的这两个接口并应用他们。
举例来说:
services.AddScoped<ISieveCustomSortMethods, SieveCustomSortMethods>();
services.AddScoped<ISieveCustomFilterMethods, SieveCustomFilterMethods>();
SieveCustomSortMethodsOfPosts
是下面这样的:
public class SieveCustomSortMethods : ISieveCustomSortMethods
{
public IQueryable<Post> Popularity(IQueryable<Post> source, bool useThenBy, bool desc) // The method is given an indicator of weather to use ThenBy(), and if the query is descending
{
var result = useThenBy ?
((IOrderedQueryable<Post>)source).ThenBy(p => p.LikeCount) : // ThenBy only works on IOrderedQueryable<TEntity>
source.OrderBy(p => p.LikeCount)
.ThenBy(p => p.CommentCount)
.ThenBy(p => p.DateCreated); return result; // Must return modified IQueryable<TEntity>
}
}
SieveCustomFilterMethods
:
public class SieveCustomFilterMethods : ISieveCustomFilterMethods
{
public IQueryable<Post> IsNew(IQueryable<Post> source, string op, string[] values) // The method is given the {Operator} & {Value}
{
var result = source.Where(p => p.LikeCount < &&
p.CommentCount < ); return result; // Must return modified IQueryable<TEntity>
}
}
配置Sieve
使用ASP.NET Core options pattern这种方式来配置SieveOption,告诉Sieve从哪里找到配置。比如:
services.Configure<SieveOptions>(Configuration.GetSection("Sieve"));
你可以在Json文件中添加配置:
{
"Sieve": {
"CaseSensitive": "boolean: should property names be case-sensitive? Defaults to false",
"DefaultPageSize": "int number: optional number to fallback to when no page argument is given. Set <=0 to disable paging if no pageSize is specified (default).",
"MaxPageSize": "int number: maximum allowed page size. Set <=0 to make infinite (default)",
"ThrowExceptions": "boolean: should Sieve throw exceptions instead of silently failing? Defaults to false"
}
}
发送一个请求
上面那些步骤你都做了的话,你可以发送一个GET请求,请求中携带排序、过滤和分页查询参数,下面一个例子:
GET /GetPosts
?sorts= LikeCount,CommentCount,-created // sort by likes, then comments, then descendingly by date created
&filters= LikeCount>10, Title@=awesome title, // filter to posts with more than 10 likes, and a title that contains the phrase "awesome title"
&page= 1 // get the first page...
&pageSize= 10 // ...which contains 10 posts
更多的信息:
sorts是按逗号分隔的有序
属性名
列表。在名称之前添加一个“-”将切换到递减排序。- filters是一组以逗号分隔的{名称①}{操作符②}{值③},下面对大括号中的这三个部分做解释:①名称,是你自定义的过滤方法中的方法名称或者SieveAttribute中的Name属性的值。你还可以通过将多个名称(作为OR的逻辑)括在括号中,并使用管道分隔符,例如。
(LikeCount|CommentCount)
>10询问LikeCount或CommentCount是否为>10。②操作符是下面要介绍的操作符中的一种(下面会介绍)。③值是会被过滤功能所采用的值。你同样可以使用多个值(作为OR逻辑),比如Title@=new|hot
会返回Title包含“new”或者“hot"的Post。 - page是要返回的分页数据的页数。
- pageSize是每一页所包含的条目数。
注意:
- 可以使用反斜杠转义值字段中的逗号和管道
- 可以在除{名称}或{操作符}字段之外的任何地方使用空格
- 如果需要在应用分页之前查看数据(例如:获取总计数),使用Apply上的可选参数来延迟分页,这里有一个例子:
//代码直接摘抄自这个项目的github上面的issure中,你可以自己打开看
From my own experience I'd like the ability to get the total count while filtering and paginating.
When paginating result.Count() will be the number of records on that page, not the total number of records. This alone doesn't give enough information to, say, power a pagination component as we don't know the number of total pages/records. Though, if I'm wrong I'd be pretty happy as I'm currently doing this as a workaround: public async Task<IActionResult> GetQuestions(SieveModel sieveModel)
{
var questions = _context.Questions.AsNoTracking();
questions = _sieveProcessor.Apply(sieveModel, questions); var total = _context.Questions.AsNoTracking();
total = _sieveProcessor.Apply(sieveModel, total, applySorting: false, applyPagination: false);
Request.HttpContext.Response.Headers.Add("X-Total-Count", total.Count().ToString()); return Ok(questions);
}
- 这里有一个如何在IEnumerable上面工作的例子:
You'll have to write a custom filter for that. Here's an example for v>=1.3.: public class SieveCustomFilterMethods : ISieveCustomFilterMethods
{
public IQueryable<Post> AuthorIsAnyOf(IQueryable<Post> source, string op, string value)
{
var result = source.Where(p => value.Split('|').Contains(p.Author));
return result;
}
} Then inject the class: services.AddScoped<ISieveCustomFilterMethods, SieveCustomFilterMethods>();. Now you can send requests in the form: & AuthorIsAnyOf == Bad Pitt|Mel Gibson Note I'm using the pipe character (|) instead of a comma because Sieve uses commas to separate filter terms.
- 另一个应用OR逻辑的例子:
You can do that with a custom filters so for example: The equivalent of your (title, body, author)@=ABC would be PostSearch@=ABC with: public class SieveCustomFilterMethods : ISieveCustomFilterMethods
{
public IQueryable<Post> PostSearch(IQueryable<Post> source, string op, string value)
{
if (op == "@=")
{
var result = source.Where(p => p.Title.Contains(value)
|| p.Body.Contains(value)
|| p.Author.Contains(value));
return result;
}
else
{
return source;
}
}
} This would save you having to send requests with the same property names repeated every time, as well as allow for any additional logic you might need. That being said, I understand the need for OR logic, especially when you need to query unknown arbitrary parameters each time. I was working on an version where a | would donate OR (similar to , currently denoting AND). I think this would allow for more complex logic than your suggested implementation - at the cost of being less concise and more redundant (ie. instead of (p1,p1)@=ABC, you'd have p1@=ABC|p2@=ABC. Let me know what you think - would that work for your use case or am I missing something? Really glad you like Sieve :D.
将查询应用于嵌套对象
你可以通过FluentApi来标记一个嵌套的对象属性,通过Attribute的方式目前还没有支持。
例子如下,使用如下模型:
public class Post {
public User Creator { get; set; }
} public class User {
public string Name { get; set; }
}
然后将Post里面的嵌套对象属性Creator的Name属性标记为可以过滤的:
// in MapProperties
mapper.Property<Post>(p => p.Creator.Name)
.CanFilter();
现在你可以发送诸如这样的请求:filters=User.Name==specific_name
创建你自己的DSL
你可以实现一个ISieveModel接口来创建你自己的DSL,你也可以使用默认的SieveModel。
操作符
Operator | Meaning |
---|---|
== |
Equals |
!= |
Not equals |
> |
Greater than |
< |
Less than |
>= |
Greater than or equal to |
<= |
Less than or equal to |
@= |
Contains |
_= |
Starts with |
!@= |
Does not Contains |
!_= |
Does not Starts with |
@=* |
Case-insensitive string Contains |
_=* |
Case-insensitive string Starts with |
==* |
Case-insensitive string Equals |
!@=* |
Case-insensitive string does not Contains |
!_=* |
Case-insensitive string does not Starts with |
处理Sieve的异常
Sieve默认情况下会默默的失败,除非你在配置服务中将ThrowExceptions 设置成true。三种定义的异常会被抛出:
SieveMethodNotFoundException:它包含了一个
MethodName
属性SieveIncompatibleMethodException:它包含了一个
MethodName
, 一个ExpectedType
和一个ActualType。
SieveException:它的InnerException属性中包含了其他的错误。
一种推荐的做法是当你在ASP.NET Core中使用Sieve时你可以使用全局异常处理中间件来处理上述这些异常。
样例程序
你可以在这里SieveTests.找到一个包含了大部分Sieve概念的样例程序
Fluent API
如果要是用Fluent Api,需要重写SieveProcessor中的MapProperties
方法(以达到这个目的)
public class ApplicationSieveProcessor : SieveProcessor
{
public ApplicationSieveProcessor(
IOptions<SieveOptions> options,
ISieveCustomSortMethods customSortMethods,
ISieveCustomFilterMethods customFilterMethods)
: base(options, customSortMethods, customFilterMethods)
{
} protected override SievePropertyMapper MapProperties(SievePropertyMapper mapper)
{
mapper.Property<Post>(p => p.Title)
.CanFilter()
.HasName("a_different_query_name_here"); mapper.Property<Post>(p => p.CommentCount)
.CanSort(); mapper.Property<Post>(p => p.DateCreated)
.CanSort()
.CanFilter()
.HasName("created_on"); return mapper;
}
}
然后注入这个新的Processor
services.AddScoped<ISieveProcessor, ApplicationSieveProcessor>();
从这里找到更多的FluentApi的例子: here.
asp.net core 排序过滤分页组件:sieve(1)的更多相关文章
- asp.net core 排序过滤分页组件:sieve(2)表达式树的复习
在Sieve组件中使用了很多关于表达式树的知识,但在我们日常的工作中写表达式树的机会是非常少的,至少在我的编程生涯中没怎么写过表达式树(可能也就是3,4次).所以,为了能够看懂Sieve里面的源代码, ...
- asp.net core MVC 过滤器之ActionFilter过滤器(二)
本系类将会讲解asp.net core MVC中的内置全局过滤器的使用,将分为以下章节 asp.net core MVC 过滤器之ExceptionFilter过滤器(一) asp.net core ...
- ASP.NET Core MVC – Tag Helper 组件
ASP.NET Core Tag Helpers系列目录,这是第五篇,共五篇: ASP.NET Core MVC – Tag Helpers 介绍 ASP.NET Core MVC – Caching ...
- 学习ASP.NET Core(08)-过滤搜索与分页排序
上一篇我们介绍了AOP的基本概览,并使用动态代理的方式添加了服务日志:本章我们将介绍过滤与搜索.分页与排序并添加对应的功能 注:本章内容大多是基于solenovex的使用 ASP.NET Core 3 ...
- drf-jwt的过滤,筛选,排序,分页组件
目录 自定义drf-jwt配置 案例:实现多方式登陆签发token urls.py models.py serializers.py views.py 案例:自定义认证反爬规则的认证类 urls.py ...
- 玩转ASP.NET Core中的日志组件
简介 日志组件,作为程序员使用频率最高的组件,给程序员开发调试程序提供了必要的信息.ASP.NET Core中内置了一个通用日志接口ILogger,并实现了多种内置的日志提供器,例如 Console ...
- [译]ASP.NET Core 2.0 视图组件
问题 如何在ASP.NET Core 2.0中使用视图组件? 答案 新建一个空项目,修改Startup类并添加MVC服务和中间件: public void ConfigureServices(ISer ...
- Asp.Net Core中利用Seq组件展示结构化日志功能
在一次.Net Core小项目的开发中,掌握的不够深入,对日志记录并没有好好利用,以至于一出现异常问题,都得跑动服务器上查看,那时一度怀疑自己肯定没学好,不然这一块日志不可能需要自己扒服务器日志来查看 ...
- ASP.NET Core MVC 之视图组件(View Component)
1.视图组件介绍 视图组件是 ASP.NET Core MVC 的新特性,类似于局部视图,但它更强大.视图组件不使用模型绑定,并且仅依赖于调用它时所提供的数据. 视图组件特点: 呈块状,而不是整个响应 ...
随机推荐
- Jenkins高级用法 - Pipeline 安装
一.总体介绍 总体介绍内容摘自 玩转Jenkins Pipeline(大宝鱼) 1.核心概念 Pipeline,简而言之,就是一套运行于Jenkins上的工作流框架,将原本独立运行于单个或者多个节点的 ...
- 【Android Studio安装部署系列】九、Android Studio常用配置以及快捷键
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 整理Android Studio的常用配置和快捷键. 常用配置 显示行号 临时显示 永久显示 File——Settings——Edi ...
- Solr 14 - SolrJ操作SolrCloud集群 (Solr的Java API)
目录 1 pom.xml文件的配置 2 SolrJ操作SolrCloud 1 pom.xml文件的配置 项目的pom.xml依赖信息请参照: Solr 09 - SolrJ操作Solr单机服务 (So ...
- 强化学习(二)马尔科夫决策过程(MDP)
在强化学习(一)模型基础中,我们讲到了强化学习模型的8个基本要素.但是仅凭这些要素还是无法使用强化学习来帮助我们解决问题的, 在讲到模型训练前,模型的简化也很重要,这一篇主要就是讲如何利用马尔科夫决策 ...
- [翻译] EF Core in Action 关于这本书
Entity Framework Core in Action Entityframework Core in action是 Jon P smith 所著的关于Entityframework Cor ...
- C++ Sqlite3的基本使用
|SQLite3简介 SQLite3只是一个轻型的嵌入式数据库引擎,占用资源非常低,处理速度比Mysql还快,专门用于移动设备上进行适量的数据存取,它只是一个文件,不需要服务器进程. SQL语句是S ...
- SQL优化 MySQL版 - 索引分类、创建方式、删除索引、查看索引、SQL性能问题
SQL优化 MySQL版 - 索引分类.创建方式.删除索引.查看索引.SQL性能问题 作者 Stanley 罗昊 [转载请注明出处和署名,谢谢!] 索引分类 单值索引 单的意思就是单列的值,比如说有 ...
- SLAM+语音机器人DIY系列:(一)Linux基础——3.Linux命令行基础操作
摘要 由于机器人SLAM.自动导航.语音交互这一系列算法都在机器人操作系统ROS中有很好的支持,所以后续的章节中都会使用ROS来组织构建代码:而ROS又是安装在Linux发行版ubuntu系统之上的, ...
- 数据库艰难求生之路(基础:创建数据库表格)part1
创建表格 1.创建表格之identity create table TableName( id ,), col_1 ), col_2 ) ) 这是一个简单的表格创建,identity这个是指在创建表 ...
- JS数组添加删除
栈是一种LIFO(Last-In-First-Out,后进先出)的数据结构著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.原文: https://www.w3cplus.com/j ...