Crping.EFCore 8.8.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Crping.EFCore --version 8.8.0
                    
NuGet\Install-Package Crping.EFCore -Version 8.8.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Crping.EFCore" Version="8.8.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Crping.EFCore" Version="8.8.0" />
                    
Directory.Packages.props
<PackageReference Include="Crping.EFCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Crping.EFCore --version 8.8.0
                    
#r "nuget: Crping.EFCore, 8.8.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Crping.EFCore@8.8.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Crping.EFCore&version=8.8.0
                    
Install as a Cake Addin
#tool nuget:?package=Crping.EFCore&version=8.8.0
                    
Install as a Cake Tool

Crping.EFCore

基于 EntityFramework Core 的数据库操作工具包基础类,支持读写分离,支持MySQL、SQL Server等,包含WebApi的增、删、改、查、分页等常用方法实现!

📄 使用指南:Keyset 游标分页见 docs/Keyset游标分页.md

版本更新说明


8.8.0

2026年8月11日 星期二

与 Crping.EFCore.Common / Crping.EFCore.Controller 同步升至 8.8.0

新功能 — Keyset 排序键支持点分路径(嵌套 DTO 提取排序值)

  • KeysetSortKey.GetValueFrom / ResolveSort 结果类型校验支持点分路径:排序键名可写为 "Stats.Heat",游标编码按点分路径逐段从投影 DTO 的嵌套对象内提取排序值(无需再把排序字段平铺到 DTO 顶层,响应可保留内嵌层级)
  • 用法:query.OrderBy(n => n.Stats == null ? 0 : n.Stats.Heat, name: "Stats.Heat").Select(n => new { ..., Stats = n.Stats == null ? new { Heat = 0, ... } : new { n.Stats.Heat, ... } })——排序分支与投影的 null 兜底语义须一致(SQL 与游标值不漂移);嵌套对象为 null 时游标编码抛带指引的 ArgumentException(不裸抛 NullReferenceException)
  • Demo 已迁移:TopicBLL.GetKeysetListAsync 返回的 items 内嵌 stats 对象({ items: [{ ..., stats: { heat, likeCount, ... } }], pageInfo })

修复 — bool 排序键谓词构建崩溃

  • KeysetPredicateBuilder.BuildCompare 对 bool 与枚举对称处理:转 int 比较(false=0 < true=1),修复按 bool 字段排序时携带游标翻页(第 2 页起)抛 InvalidOperationException(GreaterThan 未定义于 bool)→ 500 的问题

重构 — OrderBy 全能化(合并并删除 OrderByExpr)

  • KeysetQuery / OffsetQuery 的 OrderBy 升级为任意表达式排序:直接属性访问(n => n.CreatedAt)仍走按名缓存快路径(指纹格式不变,既有游标兼容);导航属性(n => n.Author.Name)/计算字段(n => n.Price * n.Quantity)走表达式重建路径(指纹附加结构签名 + 闭包捕获值)
  • OrderBy 新增可选 name 参数(与旧 OrderByExpr 一致):缺省依次取直接属性名 → 成员链最末成员名(n.Author.Name → "Name")→ 表达式结构签名;投影 DTO 场景显式传名,排序字段位于嵌套对象内时用点分路径("Stats.Heat")
  • 原 OrderByExpr 已删除(外部未使用,无兼容负担),调用处直接改名 OrderBy 即可;顺带移除 KeysetExpression.GetMemberName(旧 OrderBy 的直接属性强校验方法,升级后为死代码)
  • 工具类可见性收窄:KeysetSortKey / KeysetExpression / KeysetPredicateBuilder 降为 internal(外部零引用,缩小公共 API 面)

测试(基线 220 → 227)

  • 嵌套 DTO 点分路径翻页 + Prev、嵌套类型缺字段静态校验、嵌套对象 null 指引、TResult=object 匿名内嵌投影翻页、内嵌 + 顶层混合双键排序、bool 排序键翻页 + Prev、字符串排序键(string.CompareTo)多页翻页;原 19 例表达式排序集成测试(Keyset 15 + Offset 4)改调 OrderBy 后全部通过

8.7.0

2026年8月11日 星期二

与 Crping.EFCore.Common / Crping.EFCore.Controller 同步升至 8.7.0

破坏性变更 — 分页结果契约属性顺序调整与 required 强化

  • KeysetPage<T> / OffsetPage<T> 的 PageInfo / Pagination 属性移至 Items 之前
  • 两个属性均改为 required init(移除默认值 = new() 和 = []),调用方构造时必须显式提供所有属性
  • 迁移指南:JSON 反序列化顺序可能变化,手动构造对象时需调整属性顺序或使用命名参数

8.6.0

2026年8月10日 星期一

与 Crping.EFCore.Common / Crping.EFCore.Controller 同步升至 8.6.0

新功能 — 任意表达式排序(OrderByExpr)

  • KeysetQuery / OffsetQuery 新增 OrderByExpr(selector, ascending, name):支持按导航属性(n => n.Author.Name)与计算字段(n => n.Price * n.Quantity)排序,突破 OrderBy 的直接属性访问限制(OrderBy 约束不变)
  • 排序键名缺省时依次取:直接属性名 → 成员链最末成员名(n.Author.Name → "Name")→ 表达式结构签名;投影 DTO 场景建议显式传 name(须与 DTO 属性一致,游标编码按名提取排序值)
  • 游标指纹对任意表达式附加表达式结构签名 + 闭包捕获值:排序表达式(含闭包值)变化后旧游标抛 ArgumentException(控制器边界映射 400),不静默错页;直接属性排序指纹格式不变,旧游标兼容
  • 主键 Id 唯一性兜底判断收窄为"实体自身主键"(修复 OrderByExpr(n => n.Author.Id) 派生名恰为 "Id" 时误判已兜底的隐患);KeysetSortPlan 排序值类型改从表达式体类型推导
  • 实体结果 + 导航属性排序需先 .Apply(q => q.Include(...)) 加载导航,或改用投影 DTO;未加载或排序值本身为 null 时,游标编码抛带指引的 ArgumentException(不再裸抛 NullReferenceException)
  • 新增 KeysetExpression 表达式辅助:TryGetMemberName / ResolveSortKeyName / UnwrapBody / ReplaceParameter;直接属性排序仍走按名缓存快路径,仅任意表达式排序走表达式重建路径

破坏性变更 — 旧分页列表契约两段式(ListPage)

  • Common 新增 ListPage<T>(sealed、init-only):{ required Pagination Pagination, required List<T> Items }
  • GetListAsync(DAL / BLL / 接口)返回由 (Pagination, List<TResult>) 元组改为 ListPage<TResult>;BLL 版由返回 IActionResult(PaginationOk 包装)改为直接返回 ListPage<TResult>
  • 分页版 GetRawListAsync(page, pageSize, options)(BLL / 接口)返回由 (Pagination, List<TResult>) 改为 ListPage<TResult>;不分页版 GetRawListAsync(options / condition, rows) 返回 List<T> 不变
  • 上述方法移除 [Obsolete](旧分页 API 以 ListPage 契约保留,不再是过时方法);同步版 GetList / GetRawList 仍标记 [Obsolete]
  • WebApiResponse 新增 PaginationOk<TResult>(ListPage<TResult>) 重载;BaseDAL.List.cs / WebApiBaseBLL.List.cs region 更名(旧分页列表 → 分页列表、旧不分页列表 → 不分页列表)
  • 破坏性:公开 API 返回类型变更,调用方需迁移(元组解构、PaginationOk(pagination, list) 包装改为直接消费 ListPage)

8.5.0

2026年8月9日 星期日

与 Crping.EFCore.Common / Crping.EFCore.Controller 同步升至 8.5.0

重构(行为不变)

  • WebApiBaseBLL.Cascade 级联树构建方法 BuildCascadeTree / BuildChildrenFromDict 改 static(无实例状态依赖),NullableKeyWrapper 改主构造函数(readonly struct 保留)

代码整理(行为不变)

  • WebApiBaseBLL.List.cs / BaseDAL.List.cs region 重组:Keyset 分页 / Offset 分页拆为独立 region,旧分页列表与不分页列表 region 更名(旧分页列表 / 旧不分页列表)
  • BaseDAL.Keyset.cs / BaseDAL.Offset.cs 分页结果对象初始化顺序调整(Items 赋值移至 PageInfo / Pagination 之后),无逻辑变化

缓存体系重构(破坏性 — useCache 三态化)

  • useCache 参数 bool → bool? 三态语义:null(默认)不缓存 / true 强制缓存 / false 强制回源;源码兼容(bool 隐式转 bool?),二进制需重编译
    • 门面方法(GetAsync / GetKvpsAsync(defaultName) / TotalAsync):useCache ?? CacheEnabled(端点开关)——端点开关控制端点路径,调用方显式传参可覆盖开关
    • 共享方法(GetByIdAsync 实体版/投影版、GetRawKvpsAsync 等):只响应调用方显式传入的三态参数,不再查询任何开关——自定义业务方法显式传 useCache: true/false 自由控制缓存,与端点开关互不干扰
    • ⚠️ 行为变化:直接调用共享方法(不传 useCache)从"默认缓存"变为"默认不缓存"
  • 新增端点级缓存开关 CacheEnable(Common):9 个开关默认全关(GetDetailsAsync / GetAsync / GetDetailsForAdminAsync / GetForEditorAsync / GetForAdminEditorAsync / GetSimpleAsync / GetListItemAsync / GetKvpsAsync / GetTotalAsync),按控制器类型 RegisterCacheEnable<TController>() 注册并由构造函数同步到 BLL;删除原方法级开关 GetByIdAsync / GetRawKvpsAsync(11 → 9)
  • 缓存默认关闭:注入 ICacheManager 后读方法默认也不缓存,需显式开端点开关(端点路径)或传 useCache: true(自定义方法)

缓存方法扩展

  • GetCascadeAsync(级联树)新增三态缓存:键含加载模式(batch/recursive)+ keySelector/Condition/OrderBy/Selector 表达式指纹 + 排序/标签;QueryFunc/SelectFunc 为委托无法指纹化,非 null 时强制回源(防串数据)
  • CountAsync / ExistAsync / AnyAsync 新增三态缓存:count:{表达式指纹} / exist:{表达式指纹} 键;ExistAsync 与 AnyAsync 语义等价共享缓存键互相命中

缓存健壮性增强

  • 故障降级:缓存/版本号存储的读写异常不影响主流程——读失败按未命中回源、写失败仅记录警告、值反序列化失败回源重写、版本号存储不可用无法拼键直接回源;仅 OperationCanceledException 向上传播(取消不降级)
  • ICacheManager.GetAsync<T> 新增 CachePolicy? policy 可选参数:命中时续期滑动过期(与 GetOrAddAsync 行为统一,修复纯读不续期导致高频键过期的问题)
  • 续期节流:命中续期窗口 = 滑动 TTL 的 1/2,高 QPS 热键减少 Redis 往返(默认滑动 4h 最多每 2h 续一次);CacheManager.MaxThrottleEntries(默认 50k)超过后过滤重建清理,误删无害(下次多续一次)
  • 删除 WebApiBaseBLL 中与 CachePolicy.Default 重复定义的 DetailCachePolicy(值完全相同),详情投影缓存统一使用 CachePolicy.Default

8.4.0

2026年8月8日 星期六

与 Crping.EFCore.Common / Crping.EFCore.Controller 同步升至 8.4.0

新功能 — TimeProvider 时间源注入(可测试)

  • WebApiBaseBLL / BaseDAL 主构造函数新增可选参数 TimeProvider? timeProvider = null(默认 TimeProvider.System,与 DateTimeOffset.Now 行为一致)
  • 新增 protected TimeProvider TimeProvider 属性,BLL / DAL 子类可直接使用统一时间源
  • 审计时间字段(CreatedAt / UpdatedAt / DeletedAt)与统计过滤(TotalAsync lastDays)共 10 处 DateTimeOffset.Now 全部改由注入的 TimeProvider 提供
  • 测试可注入 FakeTimeProvider(Microsoft.Extensions.TimeProvider.Testing 包)精确控制时间、断言审计字段;DI 注册 builder.Services.AddSingleton(TimeProvider.System) 后自动注入
  • 源码兼容:可选参数,现有构造调用(位置 / 命名 / DI)零改动,未注册 TimeProvider 时行为不变;升级需重新编译(构造签名变化,二进制不兼容)

8.3.0

2026年8月8日 星期六

与 Crping.EFCore.Common / Crping.EFCore.Controller 同步升至 8.3.0

新功能 — DatabaseExtensions

  • 新增 DatabaseExtensions:Migrate<TDb>() / EnsureCreated<TDb>(isDelete) 由 Crping.EFCore.Controller 包的 Utils 类迁入(命名空间改为 Crping.EFCore),消除 Controller 包承载 EF 工具方法的不合理依赖

8.1.0

2026年8月8日 星期六

与 Crping.EFCore.Common / Crping.EFCore.Controller 同步升至 8.1.0

破坏性变更 — 分页结果契约两段式

  • GetOffsetPageAsync 返回 OffsetPage<T> → { items, pagination };GetKeysetPageAsync 返回 KeysetPage<T> → { items, pageInfo }(顶层扁平属性移除,调用方改用 page.Pagination.X / page.PageInfo.X)
  • Demo BLL 6 处 PaginationOk(pageResult.ToPagination(), pageResult.Items) 手动转换删除,直接 Ok(pageResult) 返回两段式契约

8.0.0

2026年8月7日 星期五

与 Crping.EFCore.Common / Crping.EFCore.Controller 同步升至 8.0.0

破坏性变更 — ConnectionName 只读化

  • IMyDbContextFactory.ConnectionName 由可变属性改为 { get; init; }(构造后不可修改)
  • 一个工厂实例对应一个连接目标:运行时修改连接名的代码须改为构造传参(new MyDbContextFactory<TDb>(configuration, "连接名"))或每连接一个工厂实例
  • 目的:消除 Singleton 工厂跨请求竞态(多租户数据隔离);Config.Options 字典只读查询,不再有运行时切换路径

新功能 — 缓存方法级开关(useCache)

  • 所有自动走缓存的读方法新增 bool useCache = true 可选参数,传 false 强制回源查询,实现"全局缓存配置 + 个别方法不缓存":
    • GetByIdAsync(id) / FindAsync(id) / GetModelAsync(id) / GetAsync(id)(详情)
    • GetByIdAsync(id, options/selector)(投影详情系列)
    • TotalAsync(lastDays, policy)(统计)
    • GetRawKvpsAsync / GetKvpsAsync(键值对)
  • 默认 true,现有调用零改动(source 兼容);TotalAsync() 无参重载保持无参签名,避免与 TotalAsync(int=0,...) 形成无参调用歧义

修复

  • 共享 DbContext 守卫收窄:仅拦截"会 Dispose 共享实例的切换"(读库切换仍抛异常),共享后 SetWriteDb() 空操作路径放行——修复跨 BLL 事务编排(ShareDbContext + 多 BLL 写方法)被误拦截的问题,新增 DomainTransactionTests 集成测试复现验证

缓存扩展重命名

  • AddCrpingRedisCache → AddEFCoreRedisCache、AddCrpingMemoryCache → AddEFCoreMemoryCache:方法名前缀与库名对齐(Crping.EFCore → EFCore);AddEFCoreRedisCache 改为惰性连接(首次解析 IConnectionMultiplexer 时才 ConnectionMultiplexer.Connect,避免注册即急切连接导致应用启动失败),并补充空配置参数校验

7.7.0

2026年8月7日 星期五

与 Crping.EFCore.Common / Crping.EFCore.Controller 同步升至 7.7.0

读写分离健壮性(2026-08-07)

  • DAL 写操作强制走写库:Create / Update / Delete 全部写方法入口调用 SetWriteDb()(18 处),解决"先读后写"场景(_currentReadOnly=true)下写操作落到只读副本的隐患;共享实例(_currentReadOnly=false)下为空操作,不 Dispose
  • 共享 DbContext 切换守卫:共享模式下(_isSharingDbContext)切换到会 Dispose 共享实例的 DbContext 时抛明确异常,防止跨 BLL 事务中误释放共享实例
  • 只读副本故障摘除:新增 ReadOnlyFailureCooldown(默认 30 秒冷却)+ ValidateReadOnlyOnCreate(默认开启探活)——副本连接失败进入冷却期轮询跳过,到期自动重新尝试恢复;仅连接类异常(DbException)摘除,其他异常原样抛出;单副本走快速路径不探活
  • 多从库轮询计数器溢出修复:Interlocked.Increment 结果用 uint 取模,避免计数器回绕到 int.MinValue 时 Math.Abs 溢出为负数导致负索引
  • 写后读绑定(read-your-writes):新增 ReadWriteRouting.BindReadToWrite 静态开关(默认 false,不改变现有负载分布);开启后请求内发生写操作则后续读自动绑定主库,直到请求结束(AsyncLocal 隔离请求)

破坏性变更 — 统一缓存管理(全新设计,替换旧缓存实现)

  • 新增 ICacheManager 统一缓存门面(Common 层,无 EF 依赖):泛型 GetOrAddAsync<T> / GetAsync<T> / SetAsync<T> / RemoveAsync / InvalidateAsync,内置 JSON 序列化、单飞防击穿、空值防穿透
  • 模型版本号失效:每个模型一个版本号(ICacheVersionStore),缓存键携带版本号({FullName}:v{n}:detail:{id});写操作(Create / Update / Delete)成功后只递增版本号,该模型全部缓存键原子性失效,无需枚举键,旧键由 TTL 兜底清理
  • 版本号存储双实现:RedisCacheVersionStore(StackExchange.Redis INCR 原子递增,分布式全局生效)、MemoryCacheVersionStore(Interlocked,单机/测试)
  • 注入方式变更(破坏性):WebApiBaseBLL / BaseDomain / 所有 Controller 基类的构造参数由 IDistributedCache? 替换为 ICacheManager?;IKit.Cache / ICacheBLL.CacheManager 类型同步更新;旧的 GetCacheValueAsync(int 专用)/ GetTotalCacheKey / InvalidateTotalCacheAsync 已移除
  • 自动缓存接入:GetByIdAsync / FindAsync 详情(detail:{id})、GetRawKvpsAsync 键值对(kvp:{selector}:{condition}:{ascending})、TotalAsync 统计(total:{lastDays})三类读方法自动走缓存,未注入缓存管理器时直查数据库(零开销)
  • 缓存策略 CachePolicy:滑动/绝对过期、CacheNull 空值防护开关
  • DI 注册示例(Redis):AddSingleton<ICacheVersionStore, RedisCacheVersionStore>() + AddSingleton<ICacheManager, CacheManager>()
  • 新增测试:CacheManager 命中/未命中/滑动刷新/空值防穿透/版本号失效、写操作失效、单飞防击穿

DI 一键注册(2026-08-07)

  • AddCrpingRedisCache(configuration):一行注册 IConnectionMultiplexer(单例复用连接)+ RedisCacheVersionStore + CacheManager
  • AddCrpingMemoryCache():单机/测试场景,MemoryCacheVersionStore + CacheManager
  • ⚠️ 注意:AddStackExchangeRedisCache 只注册 IDistributedCache,不注册 IConnectionMultiplexer——版本号 INCR 依赖后者,必须额外注册(AddCrpingRedisCache 已包含);业务数据存储仍需自行调用 AddStackExchangeRedisCache
  • 8.0.0 起两个方法重命名为 AddEFCoreRedisCache / AddEFCoreMemoryCache(前缀与库名对齐),AddEFCoreRedisCache 改为惰性连接 + 参数校验

缓存健壮性增强(2026-08-07)

  • 修复 Kvp 缓存键闭包冲突(正确性):CacheKeys.BuildExpressionKey 提取表达式结构签名 + 闭包捕获值,同一 lambda 位置不同捕获值时键不同,杜绝不同请求串数据(此前 Expression.ToString() 对闭包变量生成相同字符串)
  • 详情投影版接入缓存:GetByIdAsync(id, selector/options) 键含条件/投影指纹,GetDetailsAsync / GetForEditorAsync 等投影端点生效
  • 版本号本地短 TTL 缓存(CacheManager.VersionLocalCacheTtl,默认 5 秒):避免每次读请求访问 Redis 取版本号;写操作同步刷新本地值,写后立即读到新版本
  • 命中率统计:ICacheManager.Stats(按模型键聚合 Hits / Misses / HitRate),可观测性
  • 防雪崩:CachePolicy.ExpirationJitter 绝对过期时间叠加 [0, Jitter) 随机偏移,同一批键过期时间错开

7.6.0

2026年8月6日 星期四

与 Crping.EFCore.Common / Crping.EFCore.Controller 同步升至 7.6.0

Offset 偏移分页统一

  • 新增 GetOffsetPageAsync(query, page, ct):返回 OffsetPage<T> 契约(Items + Page + PageSize + RecordCount + PageCount + HasNext + HasPrev + OrderBy + Ascending),与 GetKeysetPageAsync / KeysetPage<T> 完全对称
  • 新增 OffsetQuery<TModel, TKey, TResult> 查询构建器:链式 OrderBy(未声明排序键默认 Id 降序,显式排序自动追加 Id 唯一性兜底)/ Where / Apply / Select / TagWith,与 KeysetQuery 同构
  • 旧偏移分页方法标记 [Obsolete](签名不变,完全兼容):GetListAsync(DAL/BLL)、GetRawListAsync(BLL 分页版),请迁移至 GetOffsetPageAsync
  • Controller 新增 GET /Page 端点(MethodsEnable.GetOffsetPageAsync 开关),直接返回 OffsetPage 契约
  • Demo 全部迁移:MemberController 新增 GET /OffsetPage 演示新契约直出;其余 BLL 内部切换至新 API 并保持旧响应形状
  • 适用场景提示:Offset 适合中小数据集与按页码跳转;大数据集、深分页、高频翻页请使用 Keyset 游标分页(GetKeysetPageAsync),避免大偏移(OFFSET)扫描
  • 页码越界宽容处理:page < 1 收敛为首页,page > PageCount 返回空页(不抛异常)

修复与增强(2026-08-06)

  • 分页健壮性:Offset 分页计算改用 long 中间量防 int 溢出(pageSize * (page - 1) / recordCount + pageSize),极端页码下 OFFSET 截断保护
  • 投影防护:未指定投影(Select)且结果类型与实体类型不一致时,GetOffsetPageAsync / GetKeysetPageAsync 提前抛出明确的 ArgumentException,替代运行时 InvalidCastException
  • 查询管道去重:新增 BaseDAL.Query.cs 共享辅助 BuildBaseQuery / ExecuteProjectionAsync,GetListAsync / GetOffsetPageAsync / GetKeysetPageAsync 三处统一复用(投影防护一处修改、三处生效)
  • 文件重命名:BaseDAL.OffsetPage.cs → BaseDAL.Offset.cs(与 BaseDAL.Keyset.cs 等功能名命名对齐)

Demo 修复(2026-08-06)

  • Topic 列表投影 N+1 修复:Images 改为一对多导航属性(Topic.Images + WithMany 配置),ListItemSelector 由 Db.Set<TopicImage>() 客户端评估(逐行查询)改为 EF 可翻译的相关子查询(单条 SQL);迁移快照已同步,无 schema 变更

修复与增强(2026-08-07)

  • 恢复写操作自动失效缓存:Create / Update / Delete 全部写路径在成功后自动调用 InvalidateTotalCacheAsync()(7.0.0 曾改为手动失效,现恢复自动),仅在实际写入成功(Created / NoContent / Ok / count > 0)时失效:
    • Create:CreateModelAsync、批量 CreateAsync、GetOrCreate* 系列
    • Update:UpdateModelAsync / UpdateSelectedPropsAsync / UpdateIgnoreAsync / UpdateModelListAsync / UpdateListAsync / ExecuteUpdateAsync / 三个 Toggle 状态切换
    • Delete:SoftDeleteAsync / DeleteListAsync / ExecuteDeleteAsync / ResetSoftDeleteAsync
  • 缓存键防冲突:GetTotalCacheKey 由 typeof(TModel).Name 改为 FullName(含命名空间),避免不同库/命名空间同名模型缓存键冲突
  • 缓存击穿防护(单飞):GetCacheValueAsync 每个缓存键一把 SemaphoreSlim(_cacheLocks 并发字典),并发未命中合并为一次回源查询,写缓存后其余等待请求直接读取
  • 写失败清理跟踪状态:DbUpdateConcurrencyException / DbUpdateException 后调用 Db.ChangeTracker.Clear()(BaseDAL Create / Update / Delete),避免失败状态污染同一 DbContext 的后续操作
  • 软删除补全审计字段:单条软删除若实体实现 IDeletedAt 则自动补 DeletedAt ??= DateTimeOffset.Now;批量软删除(实现 IDeletedAt)ExecuteUpdateAsync 同时写入 IsDeleted + DeletedAt
  • BaseDAL 生命周期契约:文档注释明确 Scoped 生命周期(每个请求独立实例,禁止跨请求/线程共享);Db 属性与 SetDb 增加 ObjectDisposedException.ThrowIf 防护,释放后继续访问抛明确异常
  • ResultCode 新增 Unauthorized(401):WebApiResponse.Res 映射 ResultCode.Unauthorized → Unauthorized(),用于未登录/身份验证失败场景
  • 创建冲突防护:CreateModelAsync 捕获 DbUpdateException(唯一键/主键冲突)返回 Conflict 而非 500;TryCreateAsync(models, condition) 改为整体事务(BeginTransactionAsync),任一冲突整体回滚,避免部分成功;GetOrCreateAsync 提取 GetOrCreateCoreAsync 内核逻辑,事务边界由调用方决定
  • 新增单元测试:BatchCreateTransactionTests(批量创建事务回滚)、CacheKeyInvalidationTests(写操作后缓存失效)、FactoryRoundRobinTests(读副本轮询)、Controller/ExceptionMiddlewareTests(5xx 不泄露异常消息)

7.5.0

2026年8月6日 星期四

与 Crping.EFCore.Common / Crping.EFCore.Controller 同步升至 7.5.0

破坏性变更 — Keyset 游标分页重写

  • GetKeysetListAsync / GetKeysetRawListAsync 移除,替代为 GetKeysetPageAsync(query, cursor, direction),返回 KeysetPage<T>(Items + NextCursor / PrevCursor + HasNext / HasPrev)
  • 游标为不透明 Base64Url 令牌(KeysetCursor):携带排序指纹防错配;可配置 KeysetCursor.SigningKey 启用 HMAC 签名防伪造与篡改
  • 多字段排序生成全字段行值复合比较(k1 ▷ c1 OR (k1 = c1 AND k2 ▷ c2) ...),修复首键重复时翻页丢数据问题
  • 排序键自动追加主键 Id 唯一性兜底,保证排序全序;投影 DTO 必须包含排序字段
  • 使用说明详见 docs/Keyset游标分页.md

健壮性与性能

  • KeysetQuery 解析排序方案不再修改内部状态,构建后可并发复用
  • 游标取值改用编译表达式缓存:实体路径 AOT 安全,投影 DTO 走缓存成员访问,消除逐次反射
  • BLL 层对无效游标(过期缓存/篡改)记录警告日志
  • 新增 SQLite 集成测试(翻页正确性、同值首键、反向翻页、投影、签名、篡改防护)

修复与增强(2026-08-06)

  • 修复空页游标契约:游标指向的行被删除时,HasNext/HasPrev 与游标值保持一致,不再出现"有标志无游标"的矛盾
  • 恶意/篡改游标解码异常统一包装为 ArgumentException(签名校验、JSON 反序列化、值解析全流程),不再以 500 泄漏
  • 枚举排序键解码按排序方案值类型校验(消除对程序集版本脆弱的 Type.GetType),并修复枚举排序键翻页崩溃(比较表达式转底层数值类型)
  • RangeLimit 语义修正:<1 归 1、超过 MaxPageSize 封顶;GetRawList* 的 rows<=0 表示不限制
  • KeysetPage 属性收紧为 init,响应构造后不可篡改
  • KeysetQuery.Where(bool when, ...) 新增条件式过滤重载:条件不成立时整体忽略,消除调用处分散的 if 分支
  • KeysetQuery 支持 object TResult:可直接复用 ListItemSelector(返回 object 的匿名投影)作为 Selector,游标按元素运行时类型自动取排序值(Demo 已演示 GetKeysetListAsync)

7.4.0

2026年8月3日 星期一

与 Crping.EFCore.Common / Crping.EFCore.Controller 同步升至 7.4.0

破坏性变更 — 枚举重命名

  • DalResult 枚举重命名为 ResultCode,全项目 163 处引用更新
  • 文件从 DalResult.cs 改为 ResultCode.cs

迁移指南

  • 将代码中所有 DalResult 替换为 ResultCode

7.3.0

2026年7月30日 星期三

与 Crping.EFCore.Common / Crping.EFCore.Controller 同步升至 7.3.0

破坏性变更 — 时间类型从 DateTime 改为 DateTimeOffset

  • 所有 BLL 层的 DateTime.Now 改为 DateTimeOffset.Now(WebApiBaseBLL.cs、WebApiBaseBLL.Update.cs、WebApiBaseBLL.Delete.cs)
  • 统计查询 DateTime.Today 改为 DateTimeOffset.Now(WebApiBaseBLL.Statistics.cs)
  • EntityHelper.DefaultTime 类型从 DateTime 改为 DateTimeOffset
  • EntityHelper.GenerateId() 参数 fixedTime 从 DateTime? 改为 DateTimeOffset?
  • Utils.CustomTimestamp() 参数 fixedTime 从 DateTime? 改为 DateTimeOffset?
  • EFCoreExt.UpdateTo() 中 DateTime.Now 改为 DateTimeOffset.Now

迁移指南

  • 将实体中的 DateTime 属性改为 DateTimeOffset
  • DateTime.Now 改为 DateTimeOffset.Now
  • 数据库列类型从 datetime2 改为 datetimeoffset

7.2.0

2026年7月28日 星期一

接口更新

  • MyDbContextFactory<TDb> 泛型约束从 IDbConfiguration 更新为 IAppConfiguration
  • IDbConfiguration 已删除,统一使用 IAppConfiguration

Demo 示例同步更新

  • EntityConfigure → EntityHelper:种子数据中 16 处引用已更新
  • IMyConfiguration → IAppConfiguration:TestDbContext 已更新
  • .Dom → .Domain:TopicController 已更新
  • IEnabled → IIsEnabled:StatusToggleTests 已更新

单元测试修复

  • CreateTests:修正 3 个 CreateAsync 测试断言(ObjectResult + 201 状态码替代 CreatedAtActionResult)
  • CreateTests:修正空 ID 测试,验证 GenerateId 返回空字符串时的行为

7.1.0

2026年7月28日 星期一

SQLite 数据库支持

  • EntityHelper.UseDefaultTime() 新增 sql 参数,支持不同数据库的默认时间函数(SQLite: datetime('now'),PostgreSQL: NOW(),MySQL: CURRENT_TIMESTAMP)
  • EntityHelper.UseStringKey() / UseStringBin() 新增 collation 参数,支持不同数据库的排序规则(SQLite: BINARY)
  • 消费者只需在 DbContext.OnConfiguring() 中调用 UseSqlite(ConnectionString) 即可切换到 SQLite

新增类(向后兼容 — 旧类标记 [Obsolete])

  • EntityHelper:实体配置辅助类,替代 EntityConfigure(名称更清晰)
  • WebApiIntBLL:基于 int 类型用户主键的 BLL,替代 WebApiForIntBLL
  • WebApiLongBLL:基于 long 类型用户主键的 BLL,替代 WebApiForLongBLL

新增方法

  • EntityHelper.UseUrl():URL 路径配置方法(C# 命名规范:Url 而非 URL)

重命名(向后兼容)

  • EntityConfigure → EntityHelper:旧类保留静态成员转发,扩展方法仅在新类中
  • UseURL → UseUrl:旧方法标记 [Obsolete] 并转发到新方法
  • WebApiForIntBLL → WebApiIntBLL:旧类保留并继承新类
  • WebApiForLongBLL → WebApiLongBLL:旧类保留并继承新类

代码质量

  • 修复 EntityHelper.cs region 注释拼写错误:Decimel → Decimal
  • 重命名私有常量 parent_error_in_create → ParentErrorInCreate(PascalCase)
  • 重命名私有字段 _dom → _domain(避免与 DOM 混淆)
  • 重命名文件 BaseDAL.Kvps.cs → BaseDAL.Kvp.cs,WebApiBaseBLL.Kvps.cs → WebApiBaseBLL.Kvp.cs

7.0.0

2026年7月26日 星期日

重大版本:含多项破坏性变更,下游升级请阅读完整说明

破坏性变更(必须关注)

  • DAL 层返回值由 HTTP code (int) 改为 ResultCode 枚举(200/201/204/400/403/404/409),解耦与 ASP.NET Core StatusCodes 的耦合;BaseDAL 公开方法签名变化
  • BaseDAL 和 WebApiBaseBLL 拆分为 partial class(按职责分离到独立文件:Create / Delete / Detail / Kvps / List / Persistence / Statistics / Update),部分内部 API 可见性变化(IDE 的"转到定义"层级会变)

安全性与并发

  • DAL 层捕获 DbUpdateConcurrencyException,写操作统一返回 Conflict(409);先检查实体是否存在,不存在则返回 NotFound(404)
  • 批量操作(obsolete 路径)启用事务保护(BeginTransactionAsync),updater 抛异常时回滚

性能

  • DeleteListAsync / UpdateListAsync 改用 ExecuteUpdateAsync / ExecuteDeleteAsync 服务端执行,不再加载全部数据到内存
  • Kvps 查询改用编译表达式,绕过 AsNoTracking 实体的 ChangeTracker
  • MyDbContextFactory 读副本轮询改 Interlocked.Increment 无锁化(替代 Lock + ++index)
  • IgnoreSpecialProperties 字典映射替代 10 个 if 检查

可靠性与一致性

  • BaseDAL.Dispose 模式补全:_disposed 标志防重复释放;移除冗余 GC.SuppressFinalize
  • WebApiBaseBLL 移除 Dispose,由 DI 容器统一管理 DAL 生命周期
  • 缓存层:Create / Update / Delete 不再自动调用 InvalidateTotalCacheAsync();下游若依赖 CRUD 后缓存自动失效,需改为显式调用(注意:此变更为不对称 Revert 的结果,详见 git log 92a976e ↔ 8fc943c)

API 与代码组织

  • WebApiBaseBLL 同步方法标记 [Obsolete],与 BaseDAL 对齐
  • WebApiBaseBLL 提取 PrepareForCreate / ValidateUpdatePreCheck / ValidateUpdateCore / BuildSelfOnlyCondition,消除多处重复
  • 级联查询支持 batch 模式(batchMode 参数,一次性加载全部);引入 AsyncLocal 隔离 IsVerifyOwner / GetCurrentUserId;新增 NullableKeyWrapper 解决 nullable TKey 在 Dictionary 中的约束
  • BaseDAL.SetWriteDb 恢复跟踪行为;Statistics 统一 AsNoTracking 并简化为表达式体
  • Update 错误处理提取为私有方法;Kvps 简化
  • IDomain 中未使用的 HTTP 类型依赖相关 refactor(commit 3eb4504)已被回退(65ae448),净状态未变
  • DateTime.Now → DateTime.UtcNow 改造 + 注释死代码清理(commit ff13f66)已被回退(bf06cb9),净状态未变

项目结构

  • SLN 嵌套重构:将 Crping.EFCore 项目从仓库根目录迁入 Crping.EFCore/ 子目录下(与 Common / Controller 一致),slnx 与 ProjectReference 路径相应更新

文档

  • 所有类与方法补全 XML 文档注释
  • 完整内部重构与注释微调(aa86f80 / 9c916de / 13d591c)

6.11.0

2026年6月16日 星期二
  • 优化Create,Update,GetOrCreate相关方法
  • 移除接口IDomainCommonMethods
  • 移除BaseDomain中方法的virtual修饰符
  • 升级所有相关组件版本

6.10.0

2026年6月9日 星期二
  • 删除大部分方法的virtual修饰符
  • 新增方法FirstOrDefaultAsync<TOrderKey, TResult> (IQueryOptions<TModel, TOrderKey, TResult>? options),并添加相关接口方法
  • 新增方法FirstOrDefault<TOrderKey, TResult> (IQueryOptions<TModel, TOrderKey, TResult>? options),并添加相关接口方法

6.9.2

2026年3月20日 星期五
  • 为Create相关方法添加字符串类型Id的检查与赋值逻辑,并添加异常明确的消息提示

6.9.1

2026年3月18日 星期三
  • 优化创建相关方法的Id生成逻辑

6.9.0

2026年2月26日 星期三
  • 扩展接口支持管理员权限:修改 IDetailsSelector、IEditorSelector、IGetDetails、IGetForEditor、IListItemSelector 等接口,添加管理员权限相关方法
  • 增强 WebApiBaseBLL 类:添加 DetailsSelectorForAdmin、EditorSelectorForAdmin、ListItemSelectorForAdmin 等属性,支持管理员权限的数据选择

6.8.0

2026年2月6日 星期五
  • 新增方法ToggleDeleteStatusAsync

6.7.0

2026年2月6日 星期五
  • 优化软删除相关方法逻辑
  • 新增状态切换方法ToggleEnableStatusAsync, ToggleAuditStatusAsync

6.6.0

2026年1月20日 星期二
  • 新增属性Query
  • 新增一系列求和、平均值方法
  • 新增方法MaxPageSize并优化相关命名

6.5.0

2026年1月19日 星期一
  • 新增工具类Toolkit

6.4.0

2025年12月31日 星期三
  • 删除接口ICreateAndUpdateByDto
  • 优化所有命名空间

6.3.0

2025年12月28日 星期日
  • BLL添加并实现接口新增接口ICommonSelectors<TModel, TResult>, IListItemSelector<TModel, TResult>, IDetailsSelector<TModel, TResult>, IEditorSelector<TModel, TResult>, ISimpleSelector<TModel, TResult>,IGetKvps
  • 优化方法GetKvpsAsync
  • 新增接口ICreateAndUpdateByDto

6.2.0

2025年12月25日 星期四
  • 新增接口ICommonSelectors<TModel, TResult>, IListItemSelector<TModel, TResult>, IDetailsSelector<TModel, TResult>, IEditorSelector<TModel, TResult>, ISimpleSelector<TModel, TResult>,IGetKvps
  • 优化方法GetRawKvpsAsync, GetKvpsAsync

6.1.0

2025年12月2日 星期二
  • 新增接口IDomainCommonMethods<TModel, TKey>, ICreateAsync<TModel>, IUpdateAsync<TModel, TKey>, IGetDetails<TKey>

6.0.0

2025年11月27日 星期四
  • 升级为 .net10.0
  • 适配ExecuteUpdate相关方法

5.11.0

2025年11月13日 星期四
  • 新增接口:ICommonMethods<TKey>, IGetModelSelector

5.10.0

2025年11月2日 星期日
  • 将所有列表方法的返回值从接口改为具体类型
  • 新增Keyset分页方法GetKeysetListAsync,GetKeysetRawListAsync

5.9.0

2025年9月25日 星期四
  • BaseDAL添加对IAudit,IDeletedAt的支持

5.8.0

2025年9月23日 星期二
  • 优化BLL, DAL中所有更新相关方法对特殊状态属性的更新保留,并重命名部分方法

5.7.0

2025年7月31日 星期四
  • BLL新增方法UpdateExcludeAsync
  • DAL方法UpdateAsync新增更多特殊状态属性的更新保留

5.6.0

2025年7月31日 星期四
  • 将Update相关方法的数组参数添加params

5.5.0

2025年6月18日 星期三
  • GetByOptionsAsync 与GetBySelectorAsync 重命名为 GetByIdAsync

5.4.3

2025年5月23日 星期五
  • 修复方法 SoftDeleteAsync(...)

5.4.2

2025年5月23日 星期五
  • 修复方法 SoftDeleteAsync(...)

5.4.1

2025年5月23日 星期五
  • WebApiBaseBLL 优化方法 SoftDeleteAsync(...)

5.4.0

2025年5月22日 星期四
  • WebApiBaseBLL 新增方法SoftDeleteAsync, ResetSoftDeleteAsync

5.3.0

2025年5月21日 星期三
  • 修改BaseDAL的方法 RangeLimit(...)

5.2.0

2025年4月19日 星期六
  • WebApiBaseBLL 新增方法 GetByIdAsync,GetById

5.1.1

2025年4月9日 星期三
  • 优化方法:CustomTimestamp(...)

5.1.0

2025年3月25日 星期二
  • BaseDAL新增属性MaxList,新增方法SetMaxList(...)
  • WebApiBaseBLL新增方法SetMaxList(...)
  • 所有列表方法新增对列表最大数量的控制

5.0.2

2025年3月9日 星期日
  • 统一子组件传递依赖中的组件版本

5.0.1

2025年3月9日 星期日
  • 删除未使用的引用

5.0.0

2024年11月17日 星期日
  • 升级为 .net9.0
  • 更新引用组件,并清理替换弃用的组件

4.20.0

2024年11月16日 星期六
  • AuthenticationHeaderValue 修改为 AuthHeaderValue
  • GetAuthHeaderValue 修改为 GetAuthHeaderValue

4.19.0

2024年11月14日 星期四
  • BaseDomain 新增委托 GetAuthenticationHeaderValue 以及属性 AuthenticationHeaderValue

4.18.0

2024年11月14日 星期四
  • BaseDomain 新增委托 GetAuthorization 以及属性 Authorization

4.17.0

2024年11月12日 星期二
  • 修改EntityConfigure中方法UseURL的默认值
  • 新增方法SetTable

4.16.0

2024年10月22日 星期二
  • EntityConfigure 添加方法 ToStringId(...) 并修改 GenerateId(...)
  • DefaultDate 改为 DefaultTime

4.15.0

2024年10月20日 星期日
  • 新增方法 GenerateId(...), CustomTimestamp(...)
  • 修改方法 UseStringKey(...) 的参数顺序

4.14.0

2024年10月19日 星期六
  • 新增实体配置辅助类 EntityConfigure 以及一系列常用方法

4.13.1

2024年10月16日 星期三
  • BLL 方法 GetByOptionsAsync(...) 修改条件控制逻辑,优化使用外部传入控制条件

4.13.0

2024年10月12日 星期六
  • BLL 新增接口 IConfigBLL
  • BLL 修改类 BaseDomain 的构造方法参数与相关属性
  • BaseDomain 新增方法 ShareDbContext

4.12.0

2024年10月11日 星期五
  • BLL 新增接口 IGetSimple<TKey>

4.11.1

2024年10月11日 星期五
  • BaseDomain 优化方法 SyncConfig(),并移除构造方法对 SyncConfig() 的调用

4.11.0

2024年10月11日 星期五
  • BLL 修改 CurrentUserId 属性逻辑
  • BaseDomain 修改 CurrentUserId 属性逻辑,以及构造函数,自动同步 BLL 配置
  • 升级 EFCore 相关包引用

4.10.0

2024年10月6日 星期日
  • 修复 BLL 中 IQueryOptions 的相关警告
  • BLL 新增方法 GetBySelectorAsync(...)
  • BLL 新增接口 IGetListItem
  • 方法 GetForEditorAsync(...) 修改为 GetByOptionsAsync(...)

4.9.0

2024年9月25日 星期三
  • BLL 新增接口 IGetDetails<TKey>,IGetForEditor<TKey>
  • BLL 新增方法 GetForEditorAsync
  • IQueryOptions 添加泛型约束

4.8.0

2024年9月20日 星期五
  • 跳过有BUG的 4.7.0
  • BLL新增方法SetCurrentUser
  • BaseDomain修改构造方法,新增可选参数,并新增属性
  • BaseDomain新增方法SyncConfig

4.6.0

2024年4月19日 星期五
  • 将ILogger改为泛型
  • BaseDomain新增对接口IKit的实现,增加对log,cache的支持

4.5.0

2024年4月9日 星期二
  • 类WebApiBaseBLL新增可选构造参数IToolkit,以方便注入外部工具
  • WebApiBaseBLL相关子类新增可选构造参数IToolkit,以方便注入外部工具
  • 方法CheckStringId(...)修改逻辑,以调用IToolkit中的方法

4.4.0

2024年4月7日 星期日
  • 清除不再使用的接口,如:IHostBLL等
  • 添加新接口;IGenerateId
  • 接口IDomain添加委托;GenerateId

4.3.0

2024年3月28日 星期四
  • 新增接口:ICacheBLL
  • 修改接口:IWebApiBLL,并新增IWebApiForIntBLL,IWebApiForLongBLL
  • 修改WebApiBLL,并新增WebApiForIntBLL,WebApiForLongBLL
  • 新增委托:GenerateId
  • 所有创建相关方法添加字符串类型 Id 的检查与赋值

4.2.0

2024年3月15日 星期五
  • 新增方法:Any(...),AnyAsync(...)

4.1.0

2024年3月10日 星期日
  • 新增方法:Forbidden(...),MethodNotAllowed()

4.0.0

2024年1月27日 星期六
  • 升级目标框架为.net8.0
  • 升级EF相关组件为8.0以上最新版权
  • 降级两个官方弃用的包
  • 与系列相关组件对齐版本号

3.44.1

2023年11月13日 星期一
  • SetDb(...)方法添加相同Db判断,跳过不必要的替换

3.44.0

2023-08-30
  • 新增更简洁的获取键值对方法GetKvpsAsync

3.43.0

2023-07-27
  • 为方法GetCacheValueAsync添加默认值

3.42.0

2023-07-24
  • 修改IRelatedBLL
  • 修改Update相关方法对UpdatedAt,UpdatedBy的赋值逻辑

3.41.0

2023-07-04
  • 新增IDomain<TKey>,BaseDomain<TKey>

3.40.0

2023-06-29
  • 为所有泛型参数TKey添加约束notnull
  • 为用户操作自动绑定用户ID添加TUserKey,并添加notnull约束
  • 修改所有接口类因添加TUserKey所引发的所有问题
  • 修复所有创建功能因接口差异无法自动绑定创建者ID的问题
  • 修复所有更新功能因接口差异无法自动绑定创建者ID的问题
  • 修复所有删除功能因接口差异无法自动绑定创建者ID的问题

3.39.0

2023-06-11
  • DAL新增方法GetKeysetRawListAsync(...),及其接口
  • BLL新增方法GetKeysetRawListAsync(...),及其接口
  • BLL新增方法GetKeysetListAsync(...),及其接口
  • WebApiResponse新增方法PaginationOk(...)
  • 新增Keyset分页辅助类KeysetQueryOptions

3.38.0

2023-05-25
  • 修改领域接口为IDomain,并新增委托GetCurrentUserId()
  • 修改领域基类为BaseDomain,并新增委托GetCurrentUserId()

3.37.0

2023-05-18
  • 新增领域接口IDomain<TUserKey>
  • 新增领域基类BaseDomain<TUserKey>

3.36.1

2023-05-17
  • 将方法FirstAsync(...),First(...)的返回值改为非可空类型

3.36.0

2023-05-17
  • DAL新增方法:FirstAsync(...),First(...)
  • BLL新增方法:FirstAsync(...),First(...)
  • BLL新增方法:TryCreateAsync(...),TryCreate(...)

3.35.0

2023-05-17
  • 新增方法TryCreateAsync(...),TryCreate(...)

3.34.0

2023-05-12
  • 新增种子数据接口ISeedData<T>

3.33.0

2023-05-11
  • QueryOptions新增属性SelectFunc,并在所有列表相关方法中添加对其使用

3.32.0

2023-04-26
  • 修复方法GetOrCreateAsync(...)系列方法内部查询库与创建库不一致的问题
  • 新增方法:GetCascaderAsync(...)

3.31.0

2023-04-23
  • QueryOptions新增查询标签属性Tag
  • 为所有相关搜索列表方法添加对TagWith的调用

3.30.0

2023-04-04
  • 启用可空类型
  • 修复启用可空类型后产生的所有警告

3.22.0

2023-04-04
  • DAL新增方法SetReadDbIfNull(),属性ReadIfNull
  • DAL访问属性Db时,若为Null默认初始化为ReadDb
  • BLL将默认调用的方法WriteIfNull改为ReadIfNull

3.21.0

2023-03-28
  • 将接口IConnectionString,IMyConfiguration转移到Common

3.20.1

2023-03-13
  • 将GetKvpsAsync的零值项目名称请选择改为全部

3.20.0

2023-02-24
  • DAL新增LongCountAsync,LongCount
  • BLL新增LongCountAsync,LongCount
  • BLL修改TotalAsync相关方法,新增最后几天限定统计

3.19.0

2023-02-17
  • DAL新增方法SetNoTracking,SetTrackAll
  • DAL将_db等重要对象私有化
  • DAL将所有对私有字段的访问改为公共属性,并去除所有多余的判空逻辑
  • DAL在切换为只读库里自动关闭查询跟踪
  • BLL新增属性Dal,用于统一验证
  • BLL将所有对_dal字段的引用改为属性Dal
  • BLL并去除所有多余的判空逻辑
  • BLL新增几个未添加的接口
  • BLL新增接口IKit,属性Cache,Logger

3.18.0

2023-02-03
  • 将运行时修改为net7.0

3.17.1

2023-01-13
  • BLL修改方法Task<IActionResult> TotalAsync()中的默认缓存Key

3.17.0

2023-01-13
  • BLL新增方法Task<int> TotalAsync(string, TimeSpan?, TimeSpan?)
  • BLL新增方法Task<IActionResult> TotalAsync()

3.16.0

2023-01-09
  • DAL新增方法(int, TModel) CreateModel(TModel model)
  • BLL新增方法(int, TModel) CreateModel(TModel model)
  • BLL将3.15版所有新增方法的返回值改为(int, TModel)

3.15.0

2023-01-09
  • DAL新增同步方法FirstOrDefault(condition)
  • BLL新增方法GetOrCreate(model),GetOrCreateAsync(model)
  • BLL新增方法GetOrCreate(model, condition),GetOrCreateAsync(model, condition)

3.14.0

2023-01-03
  • 更新对Crping.EFCore.Common的引用,EFCore相关组件的升级
  • 新增全局引用Global,并优化所有引用、命名空间、以及部分注释

3.13.0

2022-12-15
  • 新增接口IMyConfiguration,用于向DbContext相关类传递配置对象
  • MyDbContextFactory<TDb>类添加IConfiguration属性,并通过方法CreateDbContext将此属性赋值给DbContext相关类

3.12.0

2022-12-09
  • 添加批量删除方法ExecuteDelete,ExecuteDeleteAsync

3.11.0

2022-12-09
  • 添加批量更新方法ExecuteUpdateAsync,ExecuteUpdate

3.10.1

2022-11-28
  • 解决'pagination'添加返回值'orderBy'在不同.net版本中的返回值不同的问题

3.10.0

2022-11-28
  • DAL的列表分页返回类型'pagination'添加返回值'orderBy'

3.9.1

2022-11-26
  • 解决pagination添加返回值Ascending时queryOptions为空的Bug

3.9.0

2022-11-23
  • pagination添加返回值Ascending
  • 升级EFCore到7.0.0

3.8.0

2022-09-17
  • GetValueFromCacheAsync重命令为GetCacheValueAsync,并删除参数isRefresh
  • 新增重载方法Task<int> GetCacheValueAsync(string key, Func<Task<int>> getNewValue, TimeSpan? slidingExpiration, TimeSpan? absoluteExpirationRelativeToNow)

3.7.1

2022-09-16
  • GetPageCountFromCacheAsync 重命名为 GetValueFromCacheAsync
  • 修改GetValueFromCacheAsync的委托参数的返回类型,以支持异步方法

3.7.0

2022-09-16
  • 添加内部工具类Utils
  • 添加分页缓存方法:GetPageCountFromCacheAsync

3.6.0

2022-06-05
  • 将所有DAL中业务相关逻辑转移到BLL,并将部分强制更新字段改为可选更新

2022-05-18
  • 修改所有InitDb相关方法
  • BLL层添加SetReadDb,SetWriteDb方法

2022-04-01
  1. 更新对Crping.EFCore.Common的引用,并对齐版本号

2021-07-15:

  1. IWebApiBLL接口与基础实现类添加Read,Write属性,以实现读写分离链接调用
  2. IBaseDAL接口与与基础实现类添加Read,Write属性,以实现读写分离链接调用
  3. IBaseDAL接口与与基础实现类添加ReadOnly方法,以实现以参数的方式读写分离链接调用
  4. IWebApiBLL接口与基础实现类去除所有readOnly参数,改为链式调用

历史记录
  • 3.6.0:将所有DAL中业务相关逻辑转移到BLL,并将部分强制更新字段改为可选更新
  • 3.5.1:更新引用组件版本
  • 3.5.0:修改所有InitDb相关方法,BLL层添加SetReadDb,SetWriteDb方法
  • 3.4.0:添加IHostBLL,删除IRelatedBLL,并修改相关方法
  • 3.3.0:更新对Crping.EFCore.Common的引用,并对齐版本号
  • 3.1.0:给所有方法添加判空逻辑,DbContextFactory类改为MyDbContextFactory
  • 3.0.0:目标框架改为.net6.0,并引用EFCore6.0
  • 2.4.0:新增方法:ShareCurrentUserIdFunc,重命名方法:ShareDbContext
  • 2.3.0:新增方法 GetRawKvpsAsync,并升级EFCore到5.0.10
  • 2.2.0:添加带条件的 Include 扩展方法
  • 2.1.0:修改默认排序BUG,新增IDisposable, IAsyncDisposable
  • 2.0.2:获取列表相关方法添加默认以ID为排序方式的升降序配置
  • 2.0.1:CreateDbContext ReadOnly时添加Lock,以防多线程处理时数组越界
  • 2.0.0:使用自定义DbContextFactory,延迟创建DbContext等(重大改版!!!)
  • 1.5.3:GetKvpsAsync添加参数,修改默认排序
  • 1.5.2:修复共享DbContext时的Bug
  • 1.5.1:添加DbContext共享
  • 1.5.0:重要!!,添加并实现IRelatedBLL接口,拆分DAL,BLL为CRUD等接口
  • 1.4.1:去除GetCurrentUserID未赋值时的默认值0,暴露BUG
  • 1.4.0:增加并修改DAL、BLL层相关列表方法
  • 1.3.1:简化Get类方法重载的参数
  • 1.3.0:BLL中的列表方法添加一系列重载
  • 1.2.0:修改DAL,BLL的实现基类名称
  • 1.1.0:添加Read、Write属性以链式调用方式取代传参方式。
  • 1.0.0:包含数据库常规操作的DAL基类,WebApi常规操作的BLL基类等
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (7)

Showing the top 5 NuGet packages that depend on Crping.EFCore:

Package Downloads
Crping.EFCore.Controller

基于 Crping.EFCore 的 WebApi 控制器基类

Crping.Auth.BLL

Crping.Auth 的业务逻辑层

Crping.Auth.MySql.DAL

Crping.Auth.DAL 的 MySql 实现

Crping.AuthPolicy.BLL

Package Description

Crping.Auth.Domain

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.3.0 99 9/21/2026
10.2.2 128 9/15/2026
10.2.0 109 9/14/2026
10.1.0 102 9/13/2026
10.0.0 113 9/11/2026
9.13.0 140 9/3/2026
9.12.0 115 8/31/2026
9.11.0 117 8/31/2026
9.10.0 120 8/30/2026
9.9.0 116 8/29/2026
9.8.0 118 8/29/2026
9.7.0 125 8/26/2026
9.6.0 123 8/24/2026
9.5.0 147 8/22/2026
9.4.0 135 8/18/2026
9.3.0 124 8/18/2026
9.2.0 120 8/18/2026
9.1.2 137 8/16/2026
9.1.1 128 8/16/2026
8.8.0 129 8/11/2026
Loading failed

8.8.0 · 2026-08-11
【新功能】Keyset 排序键支持点分路径:投影 DTO 内嵌对象(如 Stats = new { Heat })可按 "Stats.Heat" 提取排序值,响应可保留嵌套层级
【修复】bool 排序键谓词构建崩溃:BuildCompare 对 bool 转 int 比较(false=0 < true=1),修复按 bool 字段排序翻第 2 页起抛 InvalidOperationException 的问题
【重构】OrderBy 全能化:KeysetQuery / OffsetQuery 的 OrderBy 支持任意服务端可翻译表达式(直接属性访问走按名缓存快路径,导航属性/计算字段走表达式重建路径),原 OrderByExpr 已删除并入 OrderBy(可选 name 参数支持点分路径提取排序值)