1、分页 在TodoItemController.cs中添加如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 [HttpGet("paged" ) ] public ActionResult<List<TodoItemVO>> GetPagedTodoItems([FromQuery] int pageNumber = 1 , [FromQuery] int pageSize = 10 ){ if (pageNumber < 1 ) pageNumber = 1 ; if (pageSize < 1 ) pageSize = 10 ; if (pageSize > 100 ) pageSize = 100 ; var pagedResult = _todoItemService.GetPagedTodoItems(pageNumber, pageSize); return Ok(pagedResult); }
在ITodoItemService.cs中添加如下代码
1 2 3 4 5 6 7 public List<TodoItemVO> GetPagedTodoItems (int pageNumber, int pageSize ) ;
在TodoItemServiceImpl.cs中添加如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public List<TodoItemVO> GetPagedTodoItems (int pageNumber, int pageSize ){ if (pageNumber < 1 ) pageNumber = 1 ; if (pageSize < 1 ) pageSize = 10 ; var todoItems = _todoItemMapper.GetPagedTodoItems(pageNumber, pageSize); var pagedItems = todoItems.Select(item => new TodoItemVO { Id = item.Id, Name = item.Name, IsComplete = item.IsComplete, CreatedAt = item.CreatedAt, UpdatedAt = item.UpdatedAt, DeletedAt = item.DeletedAt }).ToList(); return pagedItems; }
在ITodoItemMapper.cs中添加如下代码
1 2 3 4 5 6 7 8 9 public List<TodoItem> GetPagedTodoItems (int pageNumber, int pageSize ) ;
在TodoItemMapperImpl.cs中添加如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public List<TodoItem> GetPagedTodoItems (int pageNumber, int pageSize ){ return _context.TodoItems .Skip((pageNumber - 1 ) * pageSize) .Take(pageSize) .ToList(); }
2、筛选 在TodoItemController.cs中修改为如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 [HttpGet("paged" ) ] public ActionResult<List<TodoItemVO>> GetPagedTodoItems( [FromQuery ] int pageNumber = 1 , [FromQuery ] int pageSize = 10 , [FromQuery ] string ? name = null ) { if (pageNumber < 1 ) pageNumber = 1 ; if (pageSize < 1 ) pageSize = 10 ; if (pageSize > 100 ) pageSize = 100 ; var pagedResult = _todoItemService.GetPagedTodoItems(pageNumber, pageSize, name); return Ok(pagedResult); }
在ITodoItemService.cs中修改为如下代码
1 2 3 4 5 6 7 8 public List<TodoItemVO> GetPagedTodoItems (int pageNumber, int pageSize, string ? name = null ) ;
在TodoItemServiceImpl.cs中修改为如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public List<TodoItemVO> GetPagedTodoItems (int pageNumber, int pageSize, string ? name = null ){ var todoItems = _todoItemMapper.GetPagedTodoItems(pageNumber, pageSize, name); var pagedItems = todoItems.Select(item => new TodoItemVO { Id = item.Id, Name = item.Name, IsComplete = item.IsComplete, CreatedAt = item.CreatedAt, UpdatedAt = item.UpdatedAt, DeletedAt = item.DeletedAt }) .ToList(); return pagedItems; }
在ITodoItemMapper.cs中修改为如下代码
1 2 3 4 5 6 7 8 public List<TodoItem> GetPagedTodoItems (int pageNumber, int pageSize, string ? name = null ) ;
在TodoItemMapperImpl.cs中修改为如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public List<TodoItem> GetPagedTodoItems (int pageNumber, int pageSize, string ? name = null ){ IQueryable<TodoItem> query = _context.TodoItems; if (!string .IsNullOrEmpty(name)) { query = query.Where(t => t.Name != null && t.Name.Contains(name)); } return query .Skip((pageNumber - 1 ) * pageSize) .Take(pageSize) .ToList(); }
3、排序 在TodoItemController.cs中修改为如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 [HttpGet("paged" ) ] public ActionResult<List<TodoItemVO>> GetPagedTodoItems( [FromQuery ] int pageNumber = 1 , [FromQuery ] int pageSize = 10 , [FromQuery ] string ? name = null , [FromQuery ] string ? sortBy = null , [FromQuery ] string ? order = null ) { if (pageNumber < 1 ) pageNumber = 1 ; if (pageSize < 1 ) pageSize = 10 ; if (pageSize > 100 ) pageSize = 100 ; var pagedResult = _todoItemService.GetPagedTodoItems(pageNumber, pageSize, name, sortBy, order); return Ok(pagedResult); }
在ITodoItemService.cs中修改为如下代码
1 2 3 4 5 6 7 8 9 10 public List<TodoItemVO> GetPagedTodoItems (int pageNumber, int pageSize, string ? name = null , string ? sortBy = null , string ? order = null ) ;
在TodoItemServiceImpl.cs中修改为如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public List<TodoItemVO> GetPagedTodoItems (int pageNumber, int pageSize, string ? name = null , string ? sortBy = null , string ? order = null ){ var todoItems = _todoItemMapper.GetPagedTodoItems(pageNumber, pageSize, name, sortBy, order); return todoItems.Select(item => new TodoItemVO { Id = item.Id, Name = item.Name, IsComplete = item.IsComplete, CreatedAt = item.CreatedAt, UpdatedAt = item.UpdatedAt, DeletedAt = item.DeletedAt }).ToList(); }
在ITodoItemMapper.cs中修改为如下代码
1 2 3 4 5 6 7 8 9 10 public List<TodoItem> GetPagedTodoItems (int pageNumber, int pageSize, string ? name = null ,string ? sortBy = null , string ? order = null ) ;
在TodoItemMapperImpl.cs中修改为如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 public List<TodoItem> GetPagedTodoItems (int pageNumber, int pageSize, string ? name = null , string ? sortBy = null , string ? order = null ){ IQueryable<TodoItem> query = _context.TodoItems; if (!string .IsNullOrEmpty(name)) { query = query.Where(t => t.Name != null && t.Name.Contains(name)); } bool isAscending = !string .IsNullOrEmpty(order) && order.ToLower() == "asc" ; if (!string .IsNullOrEmpty(sortBy)) { switch (sortBy.ToLower()) { case "id" : query = isAscending ? query.OrderBy(t => t.Id) : query.OrderByDescending(t => t.Id); break ; case "name" : query = isAscending ? query.OrderBy(t => t.Name) : query.OrderByDescending(t => t.Name); break ; case "iscomplete" : query = isAscending ? query.OrderBy(t => t.IsComplete) : query.OrderByDescending(t => t.IsComplete); break ; case "updatedat" : query = isAscending ? query.OrderBy(t => t.UpdatedAt) : query.OrderByDescending(t => t.UpdatedAt); break ; case "createdat" : query = isAscending ? query.OrderBy(t => t.CreatedAt) : query.OrderByDescending(t => t.CreatedAt); break ; default : query = isAscending ? query.OrderBy(t => t.CreatedAt) : query.OrderByDescending(t => t.CreatedAt); break ; } } else { query = query.OrderByDescending(t => t.CreatedAt); } return query .Skip((pageNumber - 1 ) * pageSize) .Take(pageSize) .ToList(); }
4、使用Redis Redis是一种基于内存的高性能键值数据库,其核心作用在于提供快速的数据读写能力,并支持多样化的数据结构与高可用架构。以下是它的基本作用及典型使用场景:
1、基本作用
高速数据存储与访问 由于数据存储在内存中,Redis的读写速度远超传统磁盘数据库,可达到每秒数十万次操作,尤其适合处理高并发场景下的实时数据需求。例如缓存热点数据,降低数据库负载,提升系统响应速度。
多样化数据结构支持 除了基础的字符串(String)、哈希(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set),Redis还支持位图、HyperLogLog、地理空间索引等高级结构,能灵活应对复杂业务逻辑,如统计唯一用户数(UV)或地理位置计算。
数据持久化与可靠性 通过RDB快照和AOF日志两种机制,Redis可将内存数据持久化到磁盘,避免系统故障时数据丢失。同时,主从复制、哨兵模式及集群架构确保了服务的高可用性和容灾能力。
分布式系统支持 Redis支持分布式锁、集群分片及跨节点数据同步,适用于构建分布式架构中的资源协调与负载均衡,例如电商秒杀场景下的库存控制。
2、典型使用场景
缓存加速 将频繁访问的数据(如商品详情、用户信息)缓存至Redis,减少直接查询数据库的次数,显著提升响应速度。例如,电商平台的热门商品信息可通过Redis缓存,缓解数据库压力。
会话存储与状态管理 存储用户登录状态或会话信息(如购物车数据),支持无状态服务架构。用户在不同设备或服务器间切换时,仍能保持一致的会话体验。
实时排行榜与计数器 利用有序集合(Sorted Set)的自动排序特性,实现实时更新的游戏积分榜或热销商品排行。原子操作(如INCR)则支持高并发下的访问量统计或限流控制。
消息队列与异步处理 通过列表(List)或发布订阅(Pub/Sub)模式构建轻量级消息队列,实现异步任务处理。例如订单生成后,异步通知物流系统或发送用户确认邮件。
分布式锁与资源协调 使用SETNX命令实现跨服务的互斥锁,确保分布式环境下共享资源的安全访问,例如防止库存超卖或重复提交订单。
实时数据分析 结合HyperLogLog统计大规模数据集的唯一值,或利用位图记录用户活跃状态,快速生成实时统计报表,如每日活跃用户数(DAU)。
3、通过docker desktop安装Redis 1. 下载 Docker Desktop
2. 安装 Docker Desktop
3. 配置 Docker Desktop
安装完成后,启动 Docker Desktop 。
首次打开时,将出现 Docker 订阅协议,点击 Accept(接受)以继续。
随后,系统将提示用户登录。可以选择使用 GitHub 账户或 Google 账户登录。
接下来,将出现调查问卷,您可以根据个人喜好选择填写,或直接跳过此步骤。
最后,Docker Desktop 将正常启动。
4. 安装Redis
在Docker Desktop中搜寻Redis,里面有通过Docker Desktop安装Redis相关内容。
打开Terminal(终端),然后输入相关docker代码,从而运行Redis,我们可以通过Another Redis Desktop Manager连接查看数据库中的内容。并且需要将Redis设定密码。
4、ASP.NET Core中使用Redis 1、安装必要的 NuGet 包 在项目中安装 StackExchange.Redis 包,基本 Redis 客户端。Microsoft.Extensions.Caching.StackExchangeRedis则用于分布式缓存集成。
Redis客户端库比较及推荐理由
ServiceStack.Redis
简介
ServiceStack.Redis 是一个功能强大的 Redis 客户端,支持丰富的 Redis 功能。
属于 ServiceStack 框架的一部分,提供高级 API 和易用性。
支持连接池、事务、发布/订阅、Lua 脚本等功能。
优点
高级 API 封装复杂操作
支持高并发连接池
提供丰富文档和示例
缺点
商业化 :免费版功能受限,企业版需购买许可证
社区支持较少,依赖官方维护
StackExchange.Redis
简介
由 StackExchange 团队(Stack Overflow 开发者)维护,支持 .NET Core/.NET Framework。
目前最流行的 .NET Redis 客户端之一。
优点
开源免费 :无商业限制
高性能 :多路复用连接减少开销
功能全面 :支持事务、发布/订阅、Lua 脚本等
活跃社区 :用户群体庞大,更新频繁
完善文档 :提供详细示例代码
缺点
API 偏底层,需熟悉 Redis 原理
不支持连接池(但多路复用已优化性能)
CSRedis
简介
轻量级 Redis 客户端,简化 Redis 使用。
提供与 Redis 命令一一对应的 API。
优点
易用性高,快速上手
支持高并发连接池
集成 ASP.NET Core 分布式缓存和会话管理
缺点
社区支持较少(个人维护为主)
功能相对简单,适合中小项目
FreeRedis
简介
现代化 Redis 客户端,支持多种 Redis 功能。
API 设计与 Redis 命令一致。
优点
支持事务、发布/订阅、管道等
API 简洁易用
兼容单机/集群/哨兵模式
缺点
推荐使用 StackExchange.Redis 的原因
开源免费 无商业限制,适用于任何规模项目。
高性能 多路复用技术减少连接开销,单连接处理多请求。
功能全面性 覆盖 Redis 核心功能(事务、Lua 脚本、管道等),支持缓存、分布式锁等场景。
社区支持
用户群体庞大,问题解决效率高
由 StackExchange 团队持续维护,稳定性强
文档完善 提供详细文档和代码示例,降低学习成本。
企业级验证 被多家大型企业采用,性能与可靠性经过实际验证。
总结对比
特性
ServiceStack.Redis
StackExchange.Redis
CSRedis
FreeRedis
开源免费
否(商业限制)
是
是
是
社区支持
较少
活跃
较少
较少
性能
高
高
中
中
功能全面性
高
高
中
中
易用性
高
中
高
高
文档和示例
丰富
丰富
较少
较少
结论 :推荐优先选择 StackExchange.Redis,尤其适合需高性能、功能全面且开源免费的项目。其社区支持与文档完善性使其成为 .NET 生态的首选客户端。
2、配置 Redis 连接 在 appsettings.json 中添加 Redis 的连接字符串:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 { "Logging" : { "LogLevel" : { "Default" : "Information" , "Microsoft.AspNetCore" : "Warning" } } , "ConnectionStrings" : { "DefaultConnection" : "server=localhost;port=3306;database=aspnetcore;uid=root;pwd=root;" , "Redis" : "localhost:6379,password=redis,ssl=false,abortConnect=false" } , "Redis" : { "InstanceName" : "TodoApp:" } , "AllowedHosts" : "*" }
3. 在 Program.cs 中配置 Redis 在 ASP.NET Core 的依赖注入容器中注册 Redis 客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 using Microsoft.EntityFrameworkCore;using StackExchange.Redis;using WebApp.Config;using WebApp.DB;var builder = WebApplication.CreateBuilder(args );builder.Services.AddDbContext<TodoItemDbContext>(options => options.UseMySql( builder.Configuration.GetConnectionString("DefaultConnection" ), new MySqlServerVersion(new Version(8 , 0 , 34 )) ) ); builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = builder.Configuration.GetConnectionString("Redis" ); options.InstanceName = builder.Configuration.GetSection("Redis:InstanceName" ).Value; }); builder.Services.AddSingleton<IConnectionMultiplexer>(sp => { var configuration = ConfigurationOptions.Parse( builder.Configuration.GetConnectionString("Redis" )); return ConnectionMultiplexer.Connect(configuration); }); builder.Services.AddControllers(); builder.Services.RegisterAllServices(); var app = builder.Build();app.MapControllers(); app.Run();
4. 创建 Redis 服务类相关代码 IRedisCacheService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 namespace WebApp.Redis { public interface IRedisCacheService { Task<T?> GetAsync<T>(string key); Task SetAsync <T >(string key, T value , TimeSpan? expiry = null ) ; Task<bool > RemoveAsync (string key ) ; Task<bool > ExistsAsync (string key ) ; } }
RedisCacheServiceImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 using StackExchange.Redis; using WebApp.Result; namespace WebApp.Redis.Impl { public class RedisCacheServiceImpl : IRedisCacheService { private readonly IDatabase _db; private readonly ISerializer _serializer; public RedisCacheServiceImpl (IConnectionMultiplexer redis, ISerializer serializer ) { _db = redis.GetDatabase(); _serializer = serializer; } public async Task <T ?> GetAsync <T >(string key ) { var value = await _db.StringGetAsync(key); if (value .IsNull) return default ; return _serializer.Deserialize<T>(value ); } public Task SetAsync <T >(string key, T value , TimeSpan? expiry = null ) { var serializedValue = _serializer.Serialize(value ); return _db.StringSetAsync(key, serializedValue, expiry); } public Task<bool > RemoveAsync (string key ) { return _db.KeyDeleteAsync(key); } public Task<bool > ExistsAsync (string key ) { return _db.KeyExistsAsync(key); } } }
ISerializer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 namespace WebApp.Result { public interface ISerializer { string Serialize <T >(T obj ) ; T Deserialize <T >(string value ) ; } }
JsonSerializer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 namespace WebApp.Result { public class JsonSerializer : ISerializer { public string Serialize <T >(T obj ) { return System.Text.Json.JsonSerializer.Serialize(obj); } public T Deserialize <T >(string value ) { return System.Text.Json.JsonSerializer.Deserialize<T>(value ); } } }
5. 在控制器中使用 Redis 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Distributed; using WebApp.Pojo.DTO; using WebApp.Pojo.VO; using WebApp.Services; namespace WebApp.Controllers { [ApiController ] [Route("api/[controller]" ) ] public class TodoItemController : ControllerBase { private readonly ITodoItemService _todoItemService; private readonly IDistributedCache _cache; public TodoItemController ( ITodoItemService todoItemService, IDistributedCache cache ) { _todoItemService = todoItemService; _cache = cache; } [HttpGet ] public ActionResult<List<TodoItemVO>> GetAllTodoItems() { List<TodoItemVO> todoItemVOs = _todoItemService.GetAllTodoItems(); return Ok(todoItemVOs); } [HttpGet("{id}" ) ] public async Task<ActionResult<TodoItemVO>> GetTodoItemById(int id) { string cacheKey = $"TodoItem:{id} " ; string cachedValue = await _cache.GetStringAsync(cacheKey); if (!string .IsNullOrEmpty(cachedValue)) { var item = System.Text.Json.JsonSerializer.Deserialize<TodoItemVO>(cachedValue); return Ok(item); } var todoItemVO = _todoItemService.GetTodoItemById(id); await _cache.SetStringAsync( cacheKey, System.Text.Json.JsonSerializer.Serialize(todoItemVO), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30 ) }); return Ok(todoItemVO); } [HttpPost ] public ActionResult<TodoItemVO> AddTodoItem ([FromBody] TodoItemDTO todoItem ) { TodoItemVO todoItemVO = _todoItemService.AddTodoItem(todoItem); return Ok(todoItemVO); } [HttpPut("{id}" ) ] public async Task<ActionResult<TodoItemVO>> UpdateTodoItem(int id, [FromBody] TodoItemDTO todoItem) { TodoItemVO todoItemVO = _todoItemService.UpdateTodoItem(id, todoItem); string cacheKey = $"TodoItem:{id} " ; await _cache.RemoveAsync(cacheKey); return Ok(todoItemVO); } [HttpDelete("{id}" ) ] public async Task<ActionResult<TodoItemVO>> DeleteTodoItem(int id) { TodoItemVO todoItemVO = _todoItemService.DeleteTodoItem(id); string cacheKey = $"TodoItem:{id} " ; await _cache.RemoveAsync(cacheKey); return Ok(todoItemVO); } [HttpGet("paged" ) ] public ActionResult<List<TodoItemVO>> GetPagedTodoItems( [FromQuery ] int pageNumber = 1 , [FromQuery ] int pageSize = 10 , [FromQuery ] string ? name = null , [FromQuery ] string ? sortBy = null , [FromQuery ] string ? order = null ) { if (pageNumber < 1 ) pageNumber = 1 ; if (pageSize < 1 ) pageSize = 10 ; if (pageSize > 100 ) pageSize = 100 ; var pagedResult = _todoItemService.GetPagedTodoItems(pageNumber, pageSize, name, sortBy, order); return Ok(pagedResult); } } }
5、使用Java常用标准Result格式
ApiResult
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 using WebApp.Controllers; namespace WebApp.Result { public class ApiResult <T > { public int Code { get ; set ; } public string Message { get ; set ; } public T Data { get ; set ; } public static ApiResult<T> Success (T data, string message = "操作成功" ) { return new ApiResult<T> { Code = 200 , Message = message, Data = data }; } public static ApiResult<T> Fail (int code, string message, T data = default ) { return new ApiResult<T> { Code = code, Message = message, Data = data }; } public static ApiResult<T> NotFound (string message = "资源不存在" ) { return Fail(404 , message); } public static ApiResult<T> Error (string message = "服务器内部错误" ) { return Fail(500 , message); } } }
PageResult
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 namespace WebApp.Result { public class PageResult <T > { public List<T> Records { get ; set ; } public int Current { get ; set ; } public int Size { get ; set ; } public int Total { get ; set ; } public int Pages => (int )Math.Ceiling((double )Total / Size); } }
ITodoItemService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 using WebApp.Pojo.DTO; using WebApp.Pojo.Entity; using WebApp.Pojo.VO; namespace WebApp.Services { public interface ITodoItemService { public List<TodoItemVO> GetAllTodoItems () ; public TodoItemVO GetTodoItemById (int id ) ; public TodoItemVO AddTodoItem (TodoItemDTO todoItemDTO ) ; public TodoItemVO UpdateTodoItem (int id, TodoItemDTO todoItemDTO ) ; public TodoItemVO DeleteTodoItem (int id ) ; public List<TodoItemVO> GetPagedTodoItems (int pageNumber, int pageSize, string ? name = null , string ? sortBy = null , string ? order = null ) ; public int GetTodoItemCount (string ? name = null ) ; } }
TodoItemServiceImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 using WebApp.Mapper; using WebApp.Pojo.DTO; using WebApp.Pojo.Entity; using WebApp.Pojo.VO; namespace WebApp.Services.Impl { public class TodoItemServiceImpl : ITodoItemService { private readonly ITodoItemMapper _todoItemMapper; public TodoItemServiceImpl (ITodoItemMapper todoItemMapper ) { _todoItemMapper = todoItemMapper; } public List<TodoItemVO> GetAllTodoItems () { List<TodoItem> todoItems = _todoItemMapper.GetAllTodoItems(); return todoItems.Select(item => new TodoItemVO { Id = item.Id, Name = item.Name, IsComplete = item.IsComplete, CreatedAt = item.CreatedAt, UpdatedAt = item.UpdatedAt, DeletedAt = item.DeletedAt }).ToList(); } public TodoItemVO GetTodoItemById (int id ) { TodoItem todoItem = _todoItemMapper.GetTodoItemById(id); if (todoItem == null ) { throw new Exception("Todo item not found" ); } return new TodoItemVO { Id = todoItem.Id, Name = todoItem.Name, IsComplete = todoItem.IsComplete, CreatedAt = todoItem.CreatedAt, UpdatedAt = todoItem.UpdatedAt, DeletedAt = todoItem.DeletedAt }; } public TodoItemVO AddTodoItem (TodoItemDTO todoItemDTO ) { TodoItem todoItem = new TodoItem( todoId: Random.Shared.Next(), id: todoItemDTO.Id, name: todoItemDTO.Name, isComplete: todoItemDTO.IsComplete, createdAt: DateTime.Now, updatedAt: DateTime.Now); _todoItemMapper.AddTodoItem(todoItem); TodoItem todoItemCreate = _todoItemMapper.GetTodoItemById(todoItemDTO.Id); if (todoItem == null ) { throw new Exception("Todo item not found" ); } return new TodoItemVO { Id = todoItem.Id, Name = todoItem.Name, IsComplete = todoItem.IsComplete, CreatedAt = todoItem.CreatedAt, UpdatedAt = todoItem.UpdatedAt, DeletedAt = todoItem.DeletedAt }; } public TodoItemVO UpdateTodoItem (int id, TodoItemDTO todoItemDTO ) { TodoItem todoItem = _todoItemMapper.GetTodoItemById(id); if (todoItem == null ) { throw new Exception("Todo item not found" ); } todoItem.Id = todoItemDTO.Id; todoItem.Name = todoItemDTO.Name; todoItem.IsComplete = todoItemDTO.IsComplete; todoItem.UpdatedAt = DateTime.Now; _todoItemMapper.UpdateTodoItem(id, todoItem); TodoItem todoItemUpdate = _todoItemMapper.GetTodoItemById(todoItemDTO.Id); if (todoItem == null ) { throw new Exception("Todo item not found" ); } return new TodoItemVO { Id = todoItem.Id, Name = todoItem.Name, IsComplete = todoItem.IsComplete, CreatedAt = todoItem.CreatedAt, UpdatedAt = todoItem.UpdatedAt, DeletedAt = todoItem.DeletedAt }; } public TodoItemVO DeleteTodoItem (int id ) { TodoItem todoItem = _todoItemMapper.GetTodoItemById(id); if (todoItem == null ) { throw new Exception("Todo item not found" ); } TodoItemVO result = new TodoItemVO { Id = todoItem.Id, Name = todoItem.Name, IsComplete = todoItem.IsComplete, CreatedAt = todoItem.CreatedAt, UpdatedAt = todoItem.UpdatedAt, DeletedAt = todoItem.DeletedAt }; _todoItemMapper.DeleteTodoItem(id); return result; } public List<TodoItemVO> GetPagedTodoItems (int pageNumber, int pageSize, string ? name = null , string ? sortBy = null , string ? order = null ) { var todoItems = _todoItemMapper.GetPagedTodoItems(pageNumber, pageSize, name, sortBy, order); return todoItems.Select(item => new TodoItemVO { Id = item.Id, Name = item.Name, IsComplete = item.IsComplete, CreatedAt = item.CreatedAt, UpdatedAt = item.UpdatedAt, DeletedAt = item.DeletedAt }).ToList(); } public int GetTodoItemCount (string ? name = null ) { return _todoItemMapper.GetTodoItemCount(name); } } }
ITodoItemMapper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 using System.Xml.Linq; using WebApp.Pojo.Entity; namespace WebApp.Mapper { public interface ITodoItemMapper { public List<TodoItem> GetAllTodoItems () ; public TodoItem GetTodoItemById (int id ) ; public void AddTodoItem (TodoItem todoItem ) ; public void UpdateTodoItem (int id, TodoItem todoItem ) ; public void DeleteTodoItem (int id ) ; public List<TodoItem> GetPagedTodoItems (int pageNumber, int pageSize, string ? name = null , string ? sortBy = null , string ? order = null ) ; public int GetTodoItemCount (string ? name = null ) ; } }
TodoItemMapperImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 using WebApp.DB; using WebApp.Pojo.Entity; namespace WebApp.Mapper.Impl { public class TodoItemMapperImpl : ITodoItemMapper { private readonly TodoItemDbContext _context; public TodoItemMapperImpl (TodoItemDbContext todoItemDbContext ) { _context = todoItemDbContext; } public List<TodoItem> GetAllTodoItems () { return _context.TodoItems.ToList(); } public TodoItem GetTodoItemById (int id ) { return _context.TodoItems.Find(id); } public void AddTodoItem (TodoItem todoItem ) { _context.TodoItems.Add(todoItem); _context.SaveChanges(); } public void UpdateTodoItem (int id, TodoItem todoItem ) { _context.TodoItems.Update(todoItem); _context.SaveChanges(); } public void DeleteTodoItem (int id ) { var item = _context.TodoItems.Find(id); if (item != null ) { _context.TodoItems.Remove(item); _context.SaveChanges(); } } public List<TodoItem> GetPagedTodoItems (int pageNumber, int pageSize, string ? name = null , string ? sortBy = null , string ? order = null ) { IQueryable<TodoItem> query = _context.TodoItems; if (!string .IsNullOrEmpty(name)) { query = query.Where(t => t.Name != null && t.Name.Contains(name)); } bool isAscending = !string .IsNullOrEmpty(order) && order.ToLower() == "asc" ; if (!string .IsNullOrEmpty(sortBy)) { switch (sortBy.ToLower()) { case "id" : query = isAscending ? query.OrderBy(t => t.Id) : query.OrderByDescending(t => t.Id); break ; case "name" : query = isAscending ? query.OrderBy(t => t.Name) : query.OrderByDescending(t => t.Name); break ; case "iscomplete" : query = isAscending ? query.OrderBy(t => t.IsComplete) : query.OrderByDescending(t => t.IsComplete); break ; case "updatedat" : query = isAscending ? query.OrderBy(t => t.UpdatedAt) : query.OrderByDescending(t => t.UpdatedAt); break ; case "createdat" : query = isAscending ? query.OrderBy(t => t.CreatedAt) : query.OrderByDescending(t => t.CreatedAt); break ; default : query = isAscending ? query.OrderBy(t => t.CreatedAt) : query.OrderByDescending(t => t.CreatedAt); break ; } } else { query = query.OrderByDescending(t => t.CreatedAt); } return query .Skip((pageNumber - 1 ) * pageSize) .Take(pageSize) .ToList(); } public int GetTodoItemCount (string ? name = null ) { IQueryable<TodoItem> query = _context.TodoItems; if (!string .IsNullOrEmpty(name)) { query = query.Where(t => t.Name != null && t.Name.Contains(name)); } return query.Count(); } } }
最后构建了如下的工程
1、查询结果