ShardingCore需显式配置分片键、路由策略与表名映射,不支持跨库事务、动态时间分表占位符解析及自动多表分页;须手动实现安全表路由、游标分页与连接隔离。

ShardingCore 能帮你绕过 EF Core 原生限制,但必须理解它不自动解决跨库事务、动态时间分表拼接、分页性能退化这些核心问题。
ShardingCore 的 DbContext 注册必须显式指定分片键和路由策略
它不是“加个 NuGet 就自动分表”的黑盒。你得在 AddShardingDbContext 里明确告诉它:哪个字段是分片依据、怎么算表名、是否启动时建表。
-
UseCustomShardingKey((convention, props) => convention.Property(u => u.UserId))这行必须写对——字段名拼错或类型不匹配会导致路由失效,所有数据都进默认表 -
UseShardingTableStrategy<UserTableStrategy>()中的UserTableStrategy必须继承AbstractShardingTableStrategy<T>,且GetShardingTable返回的表名必须与数据库中真实存在的表名完全一致(大小写、前缀、下划线) - 若启用
CreateShardingTableOnStart = true,要确保连接字符串有 DDL 权限;否则启动报错Cannot find object "xxx" because it does not exist
按时间分表时,ShardingCore 不支持运行期动态解析 {yyyyMM} 占位符
EF Core 的 [Table("log_{yyyyMM}")] 是编译期常量,ShardingCore 同样无法在查询执行时自动替换。你必须自己实现 IShardingTableRoute 或重写 GetShardingTable,并手动校验输入时间是否在白名单内。
- 别把用户传入的
DateTime直接格式化后拼进表名——log_{DateTime.Now.ToString("yyyyMM")}是高危 SQL 注入点 - 正确做法:先用
DateTime.SpecifyKind(input, DateTimeKind.Utc)统一时区,再取input.Year * 100 + input.Month得到整数键,查配置字典映射到合法表名(如202404 → log_202404) - 跨月查询(如查 2024-03 到 2024-05)不能靠
.Where(x => x.CreatedAt >= start && x.CreatedAt <= end)——ShardingCore 默认只路由单表,多表 UNION 需手动拼FromSqlRaw
跨分表分页必须放弃 OFFSET/LIMIT,改用游标或汇总索引
ShardingCore 对 Skip(10000).Take(20) 的处理是:在每个子表分别 Skip/Take,再合并结果——这会扫遍所有分表,性能断崖式下跌。
- 真实场景下,
OFFSET 10000在 100 张分表上等于执行 100 次全表扫描 - 游标分页要求业务字段(如
CreatedAt+Id)有联合索引,且查询条件带WHERE CreatedAt > @lastTime AND (CreatedAt = @lastTime AND Id > @lastId) - 如果必须用页码,建议另建汇总表(如
log_summary),每天凌晨跑 job 把各分表的记录数、最大/最小时间聚合进去,分页时先查汇总表定位目标分表范围
最易被忽略的是连接生命周期管理:ShardingCore 内部仍复用 EF Core 的 DbContext 生命周期(Scoped),但不同租户或不同分片的请求若共享同一个 DbContext 实例,SaveChanges() 可能写错库——务必确认 DI 容器中 DbContext 是 Scoped 作用域,且每次 HTTP 请求新建实例。


















