Skip to content

Add FieldShardPolicy: business-field-based table sharding strategy#85

Open
Soar360 with Copilot wants to merge 3 commits into
masterfrom
copilot/add-field-based-sharding-strategy
Open

Add FieldShardPolicy: business-field-based table sharding strategy#85
Soar360 with Copilot wants to merge 3 commits into
masterfrom
copilot/add-field-based-sharding-strategy

Conversation

Copilot AI commented May 22, 2026

Copy link
Copy Markdown
Contributor
  • XUnitTest.XCode/EntityTests/SqlTests.cs 增加列表 Save 分表测试(TimeShardPolicy)
  • XUnitTest.XCode/EntityTests/SqlTests.cs 增加列表 Save 分表测试(FieldShardPolicy)
  • 最小修复 EntityExtension.Save 批量场景下的分表路由:按分片会话分组后分别 BatchSave
  • 新增 EntityExtension.GroupByShardSession(internal)供 Save 复用和测试校验
  • 运行定向测试验证
    • SqlTests.ListSave_TimeShardPolicy
    • SqlTests.ListSave_FieldShardPolicy
    • FieldShardPolicyTests
  • 运行 codeql_checker 安全检查(工具超时,按提示未重试)

Copilot AI linked an issue May 22, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Add field-based sharding strategy for logs Add FieldShardPolicy: business-field-based table sharding strategy May 22, 2026
Copilot AI requested a review from Soar360 May 22, 2026 02:10
@nnhy nnhy marked this pull request as ready for review July 15, 2026 03:58
Copilot AI review requested due to automatic review settings July 15, 2026 03:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

本 PR 为 XCode 增加“按业务字段值分表”的新策略 FieldShardPolicy,并补齐批量 Save 在自动分表场景下的路由分组逻辑,同时新增/扩展单元测试与文档,帮助多租户等场景按字段值稳定落表。

Changes:

  • 新增 XCode.Shards.FieldShardPolicy:按指定字段值进行分库/分表路由,并支持从等值查询表达式中提取分片。
  • 修复 EntityExtension.Save 批量保存时的自动分表路由:新增 GroupByShardSession,按分片会话分组后分别执行 BatchSave
  • 新增/增强测试与文档:覆盖 FieldShardPolicy 的行为、SQL 路由以及列表 Save 的分表写入验证。

影响(按仓库模板补充):

  • 公共 API:是(新增 FieldShardPolicy 公共类型;EntityExtension 增加 internal 辅助方法对外无破坏,但会影响行为/测试)。
  • 性能影响:低(批量 Save 增加一次分组遍历;换来正确路由)。

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
XCode/Shards/FieldShardPolicy.cs 新增业务字段分片策略实现(按字段值路由、表达式提取等值条件)
XCode/Entity/EntityExtension.cs 批量 Save 自动分表时按分片会话分组后分别 BatchSave,并新增 GroupByShardSession 复用
XUnitTest.XCode/Shards/FieldShardPolicyTests.cs 新增 FieldShardPolicy 单测与 SQL 路由集成测试
XUnitTest.XCode/EntityTests/SqlTests.cs 增加列表 Save 在 TimeShardPolicy/FieldShardPolicy 下的分表路由测试
Doc/Shards分配策略与路由.md 文档补充 FieldShardPolicy 的定位、能力与示例

Comment on lines 245 to +249
if (valid) others = others.Valid(true);
rs += BatchSave(session, others, null);
if (useShard)
{
var groups = GroupByShardSession(others, fact, session);
foreach (var item in groups)
Comment on lines +86 to +96
if (ConnPolicy.IsNullOrEmpty() && TablePolicy.IsNullOrEmpty()) return null;

if (Factory == null) throw new XCodeException("字段分表策略要求指定实体工厂!");
var table = Factory.Table;

var connName = table.ConnName;
var tableName = table.TableName;
if (!ConnPolicy.IsNullOrEmpty()) connName = String.Format(ConnPolicy, connName, fieldValue);
if (!TablePolicy.IsNullOrEmpty()) tableName = String.Format(TablePolicy, tableName, fieldValue);

return new(connName, tableName);
Comment on lines +15 to +16
public class FieldShardPolicyTests
{
Comment on lines +239 to +245
// 字段异步加载,等待短暂时间
System.Threading.Thread.Sleep(200);

var model = policy.Shard(3000);

Assert.NotNull(model);
Assert.Equal("Log2_3000", model.TableName);
Comment on lines +278 to +296
try
{
var log = new Log2
{
Action = "字段分表",
Category = "Test",
CreateUserID = 1000,
};
log.Insert();

Assert.Contains("Log2_1000", sql);
Assert.StartsWith("[test] Insert Into Log2_1000(", sql);
}
catch { }
finally
{
Log2.Meta.ShardPolicy = null;
DAL.LocalFilter = null;
}
Comment on lines +311 to +331
try
{
var log = new Log2
{
Action = "字段分表",
Category = "Test",
CreateUserID = 2000,
};
log.Insert();

log.Category = "Updated";
log.Update();

Assert.Contains("Log2_2000", sqls[^1]);
}
catch { }
finally
{
Log2.Meta.ShardPolicy = null;
DAL.LocalFilter = null;
}
Comment on lines +346 to +367
try
{
var log = new Log2
{
Action = "字段分表",
Category = "Test",
CreateUserID = 3000,
};
log.Insert();

log.Delete();

var deleteSql = sqls.LastOrDefault(s => s.Contains("Delete"));
Assert.NotNull(deleteSql);
Assert.Contains("Log2_3000", deleteSql);
}
catch { }
finally
{
Log2.Meta.ShardPolicy = null;
DAL.LocalFilter = null;
}
Comment on lines +382 to +395
try
{
Log2.FindAll(Log2._.CreateUserID == 9000);

sqls.RemoveAll(e => e.EndsWith("sqlite_master"));
Assert.NotEmpty(sqls);
Assert.Contains("Log2_9000", sqls[^1]);
}
catch { }
finally
{
Log2.Meta.ShardPolicy = null;
DAL.LocalFilter = null;
}
Comment on lines +421 to +429
if (sqls.Count > 0)
{
var inserts = sqls.Where(e => e.Contains("Insert Into", StringComparison.OrdinalIgnoreCase)).ToList();
if (inserts.Count > 0)
{
Assert.All(inserts, s => Assert.Contains(tableName, s, StringComparison.OrdinalIgnoreCase));
Assert.DoesNotContain(inserts, s => s.Contains("Insert Into Log2(", StringComparison.OrdinalIgnoreCase));
}
}
Comment on lines +482 to +490
if (sqls.Count > 0)
{
var inserts = sqls.Where(e => e.Contains("Insert Into", StringComparison.OrdinalIgnoreCase)).ToList();
if (inserts.Count > 0)
{
Assert.All(inserts, s => Assert.Contains(tableName, s, StringComparison.OrdinalIgnoreCase));
Assert.DoesNotContain(inserts, s => s.Contains("Insert Into Log2(", StringComparison.OrdinalIgnoreCase));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

增加按业务自动分表策略

3 participants