TORM.TaosData 2.0.90

dotnet add package TORM.TaosData --version 2.0.90
                    
NuGet\Install-Package TORM.TaosData -Version 2.0.90
                    
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="TORM.TaosData" Version="2.0.90" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="TORM.TaosData" Version="2.0.90" />
                    
Directory.Packages.props
<PackageReference Include="TORM.TaosData" />
                    
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 TORM.TaosData --version 2.0.90
                    
#r "nuget: TORM.TaosData, 2.0.90"
                    
#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 TORM.TaosData@2.0.90
                    
#: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=TORM.TaosData&version=2.0.90
                    
Install as a Cake Addin
#tool nuget:?package=TORM.TaosData&version=2.0.90
                    
Install as a Cake Tool

<p align="center"> <img src="logo.svg" width = "400" height = "200" alt="TORM Logo"/> </p>

<h1 align="center">TORM - 高性能 .NET ORM 框架</h1>

<div align="center">

License NuGet .NET

轻量级、高性能、功能丰富的对象关系映射框架

TGateway 生态系统中的 ORM 组件,专为高性能场景设计。

</div>


中文

📖 项目简介

TORM 是一个为 .NET 平台设计的轻量级、高性能数据访问组件。TORM 核心和四个关系型 provider 提供完整 ORM 能力;QuestDB、TDengine 与 Apache IoTDB 扩展包使用各数据库的原生协议,提供 schema、批量写入和查询能力,不伪装成关系型 ORM,也不暴露虚假的事务、Queryable 或 Upsert 语义。

✨ 核心特性

🚀 高性能设计
  • AOT:支持AOT编译
  • 表达式树解析:高效的 LINQ 表达式到 SQL 转换
  • 批量操作优化:支持 BulkCopy 高性能批量插入/更新
🗄️ 多数据库支持
数据库 NuGet/项目 访问模型 当前能力
MySQL / MariaDB TORM.MySql 关系型 ORM CRUD、CodeFirst、事务、分表、BulkCopy、原子 Upsert
SQL Server TORM.SqlServer 关系型 ORM CRUD、CodeFirst、事务、分表、BulkCopy、原子 Upsert
PostgreSQL TORM.PostgreSql 关系型 ORM CRUD、CodeFirst、事务、分表、BulkCopy、原子 Upsert
SQLite TORM.Sqlite 关系型 ORM CRUD、CodeFirst、事务、分表和批量操作
QuestDB TORM.QuestDb 原生 REST SQL + CSV /imp 独立 schema、表维护、TTL、临时 CSV 分批导入、拒绝行与提交状态、原生查询
TDengine TORM.TaosData 显式 Native / WebSocket database、stable、subtable、KEEP、非 ADO row reader、Schemaless 写入结果
Apache IoTDB 2.0.8 TORM.IoTDB Native API Tree / Table 双模型 schema、CodeFirst、Record/Tablet 分批写入、连接池和原生查询

关系型 ORM 与时序原生客户端是明确分层的两组能力。QuestDB、TDengine 和 IoTDB 不注册 IDbProvider,也不支持 OrmClient.Queryable<T>();需要完整 ORM 语义时应使用前四种关系型 provider。

💡 丰富的功能

基础 CRUD 操作

高级功能

  • 🔹 Code First:自动创建/更新数据库表结构
  • 🔹 分表分库:支持时间分表、数量分表策略
  • 🔹 批量操作:BulkCopy 高性能批量导入
  • 🔹 事务管理:支持同步/异步事务
  • 🔹 AOP 拦截:SQL 执行前后拦截,日志记录
  • 🔹 JSON 支持:原生 JSON 类型支持
  • 🔹 全局分表语义:实体更新/删除按分表列路由,Distinct、Count、排序和分页在跨表结果上统一执行
  • 🔹 一致写入列策略:Insertable、Savable 和各关系型 BulkCopy 统一处理 identity 与 IsOnlyIgnoreInsert
  • 🔹 安全 SQL 方言:标识符转义、LIKE 字面量转义和比较方式由 provider 方言配置,不在表达式访问器中硬编码数据库类型
  • 🔹 并发保存:数据库原生 Upsert 保持原子语义,fallback 的存在性查询和写入复用同一连接与事务

⏱️ 时序数据库原生客户端

QuestDB

TORM.QuestDb 保留 QuestDB REST /exec 查询和 /imp 导入协议。每个导入批次使用一个临时 CSV 文件并在成功、拒绝、取消或异常后删除;只有服务端明确接受后才返回 Committed,部分拒绝和全部拒绝都会抛出包含数量与原始响应的异常。

using QuestDbDriver;
using TORM.QuestDb;

using var client = new QuestDbClient(new ConnectionStringBuilder("host=127.0.0.1;port=9000"));
var tables = new QuestDbTableClient(client);
await tables.EnsureTableAsync<SensorRow>();

var writer = new QuestDbCsvBulkWriter<SensorRow>(client) { BatchSize = 1000 };
var result = await writer.WriteAsync(rows);
if (result.CommitState != QuestDbCommitState.Committed)
    throw new InvalidOperationException("QuestDB batch was not committed.");
Apache IoTDB

连接串必须显式指定 Model=tree 或 Model=table。Tree 模型需要 RootPath,Table 模型需要 Database;同一个客户端不会在两种模型之间自动探测或失败回退。

using TORM.IoTDB;

var options = IoTdbConnectionOptions.Parse(
    "DataSource=127.0.0.1;Port=6667;Username=root;Password=root;" +
    "Model=tree;RootPath=root.gateway;PoolSize=2;FetchSize=128;ZoneId=UTC");

await using var client = new IoTdbClient(options);
await client.TreeCodeFirst.InitDeviceSchemaAsync<SensorPoint>("device_1001");
var writer = client.CreateTreeWriter<SensorPoint>("device_1001");
writer.BatchSize = 500;
await writer.InsertAsync(points);

Table 模型使用 IoTdbTableSchema、TableCodeFirst 和 CreateTableWriter<T>();Tree 模型使用 device path、measurement、TreeCodeFirst 和 CreateTreeWriter<T>()。两种模型的查询都返回 IoTdbQueryResult,时间以 UTC 毫秒进入原生协议。

TDengine

TDengine 连接必须显式选择 Protocol=Native 或 Protocol=WebSocket。当前客户端直接管理 transport 和结果生命周期,不再提供 DbConnection、DbCommand、DbDataReader 或 TaosDataOrmClient 兼容外壳。

using TORM.TaosData;

var options = TdengineConnectionOptions.Parse(
    "Host=127.0.0.1;Port=6041;Username=root;Password=taosdata;Protocol=WebSocket");
using var client = new TdengineClient(options);
if (!client.CheckHealth()) throw new InvalidOperationException("TDengine is unavailable.");

var schema = new TdengineSchemaClient(client);
schema.EnsureDatabase("telemetry");
using var reader = client.Query("SELECT server_version() AS version");

Native/WebSocket 的真实异步和取消能力由 client.Capabilities 明确报告;客户端不会用 Task.Run 伪造异步,也不会在协议失败时自动切换 transport。

📊 性能测试

TORM 与国内主流 ORM 框架 的Sqlite性能对比测试结果:


BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.8037/25H2/2025Update/HudsonValley2)
Intel Core Ultra 9 285H 2.90GHz, 1 CPU, 16 logical and 16 physical cores
.NET SDK 10.0.103
  [Host]    : .NET 10.0.3 (10.0.3, 10.0.326.7603), X64 RyuJIT x86-64-v3
  .NET 10.0 : .NET 10.0.3 (10.0.3, 10.0.326.7603), X64 RyuJIT x86-64-v3

Job=.NET 10.0  Runtime=.NET 10.0  

Method Mean Error StdDev Median Ratio RatioSD Gen0 Gen1 Gen2 Allocated Alloc Ratio
TORM_BulkInsert_10000 29,483.870 μs 564.6185 μs 554.5309 μs 29,662.345 μs 1.00 0.03 1062.5000 - - 13392.2 KB 1.00
SqlSugar_BulkInsert_10000 54,989.997 μs 1,048.1157 μs 1,076.3376 μs 55,272.167 μs 1.00 0.03 2833.3333 1000.0000 166.6667 34263.76 KB 1.00
FreeSql_BulkInsert_10000 537,387.137 μs 14,137.7720 μs 41,240.5475 μs 553,427.500 μs 1.01 0.12 5000.0000 1000.0000 - 64690.97 KB 1.00
TORM_BulkInsert_50000 156,769.159 μs 1,091.2339 μs 967.3505 μs 156,778.888 μs 1.00 0.01 5250.0000 - - 66934.26 KB 1.00
SqlSugar_BulkInsert_50000 268,856.227 μs 3,064.4750 μs 2,866.5118 μs 269,124.600 μs 1.00 0.01 14000.0000 4000.0000 1000.0000 168710.47 KB 1.00
FreeSql_BulkInsert_50000 2,791,199.208 μs 55,809.9648 μs 97,746.6592 μs 2,802,945.200 μs 1.00 0.05 26000.0000 1000.0000 - 323409.88 KB 1.00
TORM_BulkUpdate_50000 99,459.911 μs 967.6688 μs 905.1580 μs 99,733.850 μs 1.00 0.01 5333.3333 - - 66933.79 KB 1.00
SqlSugar_BulkUpdate_50000 182,485.632 μs 2,967.7149 μs 2,630.8020 μs 182,848.775 μs 1.00 0.02 14500.0000 4000.0000 1500.0000 168710.39 KB 1.00
FreeSql_BulkUpdate_50000 2,588,248.118 μs 51,038.1952 μs 52,412.4689 μs 2,598,517.600 μs 1.00 0.03 42000.0000 1000.0000 - 521759.37 KB 1.00
TORM_DeleteBatch_10000 7.996 μs 0.0541 μs 0.0480 μs 8.006 μs 1.00 0.01 0.1831 - - 2.4 KB 1.00
SqlSugar_DeleteBatch_10000 69.195 μs 1.0972 μs 1.0263 μs 69.525 μs 1.00 0.02 0.9155 - - 11.49 KB 1.00
FreeSql_DeleteBatch_10000 65.489 μs 0.5363 μs 0.4754 μs 65.528 μs 1.00 0.01 0.5493 - - 7.01 KB 1.00
TORM_GetList 9.035 μs 0.0527 μs 0.0493 μs 9.045 μs 1.00 0.01 0.5035 - - 6.2 KB 1.00
SqlSugar_GetList 90.299 μs 1.7914 μs 3.6995 μs 90.835 μs 1.00 0.07 2.0752 0.9766 - 25.61 KB 1.00
FreeSql_GetList 66.647 μs 1.3142 μs 2.2316 μs 67.329 μs 1.00 0.05 0.8545 0.7935 - 10.76 KB 1.00
TORM_InsertBatch_10000 29,821.968 μs 117.4661 μs 104.1306 μs 29,839.409 μs 1.00 0.00 1062.5000 - - 13391.97 KB 1.00
SqlSugar_InsertBatch_10000 119,720.489 μs 1,983.6632 μs 1,758.4657 μs 119,777.158 μs 1.00 0.02 6500.0000 3166.6667 1000.0000 72158.74 KB 1.00
FreeSql_InsertBatch_10000 562,874.180 μs 3,067.5205 μs 2,869.3606 μs 562,098.900 μs 1.00 0.01 5000.0000 1000.0000 - 64691.03 KB 1.00
TORM_InsertBatch_50000 156,858.300 μs 1,981.4147 μs 1,756.4725 μs 156,255.650 μs 1.00 0.02 5000.0000 - - 66934.18 KB 1.00
SqlSugar_InsertBatch_50000 587,029.233 μs 8,298.3128 μs 6,478.7768 μs 587,832.350 μs 1.00 0.02 28000.0000 13000.0000 2000.0000 343406.52 KB 1.00
FreeSql_InsertBatch_50000 2,743,381.907 μs 22,418.0622 μs 19,873.0282 μs 2,748,549.050 μs 1.00 0.01 26000.0000 1000.0000 - 323409.86 KB 1.00
TORM_SaveBatchUpsert_1000 2,488.677 μs 13.5737 μs 11.3346 μs 2,487.567 μs 1.00 0.01 109.3750 - - 1361.35 KB 1.00
TORM_SaveBatch_1000 3,214.556 μs 52.0409 μs 48.6791 μs 3,198.125 μs 1.00 0.02 156.2500 15.6250 - 2098.54 KB 1.00
SqlSugar_SaveBatch_1000 116,875.679 μs 2,299.9455 μs 2,361.8747 μs 116,837.275 μs 1.00 0.03 7500.0000 1000.0000 - 96188.28 KB 1.00
FreeSql_SaveBatch_1000 6,921.216 μs 136.1796 μs 127.3824 μs 6,879.202 μs 1.00 0.03 234.3750 117.1875 70.3125 2566.44 KB 1.00
TORM_SaveBulk_50000 130,866.535 μs 2,607.0517 μs 7,003.6756 μs 132,598.750 μs 1.00 0.08 5500.0000 - - 67716.66 KB 1.00
SqlSugar_SaveBulk_50000 6,335,388.058 μs 124,308.3524 μs 170,154.6902 μs 6,390,547.400 μs 1.00 0.04 712000.0000 60000.0000 9000.0000 8634677.2 KB 1.00
FreeSql_SaveBulk_50000 199,689.818 μs 3,965.4261 μs 11,184.5554 μs 202,523.525 μs 1.00 0.08 8500.0000 2000.0000 500.0000 129874.98 KB 1.00
TORM_UpdateBatch_1000 2,059.663 μs 13.8345 μs 12.9408 μs 2,055.851 μs 1.00 0.01 109.3750 - - 1344.37 KB 1.00
SqlSugar_UpdateBatch_1000 53,523.906 μs 1,172.7374 μs 3,364.8036 μs 54,097.327 μs 1.01 0.11 909.0909 727.2727 181.8182 11012.93 KB 1.00
FreeSql_UpdateBatch_1000 53,324.506 μs 650.2690 μs 608.2620 μs 53,067.340 μs 1.00 0.02 800.0000 200.0000 - 10461.04 KB 1.00

可以看出,TORM无论是速度还是内存占用都表现优异,得益于TORM是一个没有任何历史包袱的项目,其高性能设计和批量操作优化,在大数据量场景下表现尤为突出。

注:实际性能因数据库类型、数据量、硬件配置等因素会有所不同。建议在实际项目环境中进行测试。

项目结构

TORM/
|-- analyzer/TORM.Generators/     源生成器
|-- src/TORM/                     ORM 核心
|-- src/TORM.Sqlite/              SQLite 驱动
|-- src/TORM.MySql/               MySQL/MariaDB 驱动
|-- src/TORM.SqlServer/           SQL Server 驱动
|-- src/TORM.PostgreSql/          PostgreSQL 驱动
|-- src/TORM.QuestDb/             QuestDB REST SQL、schema 与 CSV writer
|-- src/TORM.IoTDB/               Apache IoTDB Native API Tree/Table 双模型扩展
|-- src/TORM.TaosData/            TDengine Native/WebSocket 原生客户端
|-- samples/TORM.AotDemo/         AOT 示例
|-- benchmark/TORM.Benchmark/     BenchmarkDotNet 基准项目
`-- test/TORM.Test/               自动化测试

构建与测试

dotnet restore TORM.slnx
dotnet build TORM.slnx -c Release
dotnet test test/TORM.Test/TORM.Test.csproj -c Release

真实数据库集成测试使用 SQLite 加六个 Docker 服务:MySQL、PostgreSQL、SQL Server、QuestDB、TDengine 和 Apache IoTDB 2.0.8。固定镜像、端口、账号和连接串保存在 test/TORM.Test/docker-compose.yml 与 test/TORM.Test/docker-test.env。

docker compose -f test/TORM.Test/docker-compose.yml up -d
docker compose -f test/TORM.Test/docker-compose.yml ps
dotnet test test/TORM.Test/TORM.Test.csproj --configuration Release

完整连接变量和 Windows Docker Desktop 注意事项见 数据库集成测试说明,当前生产变更与测试名称的逐项映射见 测试覆盖矩阵。

2026-08-30 的完整 Release 实测结果为 3808/3808 通过、0 失败、0 跳过;测试覆盖四种关系型 provider 的真实 CRUD/事务/分表/索引/BulkCopy,以及 QuestDB、TDengine、IoTDB 的真实原生协议闭环。

运行基准测试:

dotnet run -c Release --project benchmark/TORM.Benchmark/TORM.Benchmark.csproj
基础配置
using TORM;

// 创建 ORM 客户端
using var ormClient = new OrmClient(new OrmConnectionConfig
{
    DatabaseType = OrmDbType.MySql,
    ConnectionString = "Server=localhost;Database=test;Uid=root;Pwd=password;"
});
定义实体
[OrmTable(TableName = "users")]
public class User
{
    [OrmColumn(IsPrimaryKey = true, IsIdentity = true)]
    public long Id { get; set; }
    
    [OrmColumn(ColumnName = "user_name", Length = 50)]
    public string Name { get; set; }
    
    public int Age { get; set; }
    
    public DateTime CreateTime { get; set; }
}
Code First 自动建表
// 自动创建表结构
await ormClient.CodeFirst.InitTableAsync<User>();

📚 功能详解

查询操作
// 基础查询
var list = await ormClient.Queryable<User>().ToListAsync();

// 条件查询
var adults = await ormClient.Queryable<User>()
    .Where(u => u.Age >= 18)
    .ToListAsync();

// 分页查询(返回 PagedList<T>,包含总数)
var page = await ormClient.Queryable<User>()
    .Where(u => u.IsActive)
    .OrderByDescending(u => u.CreateTime)
    .ToPageListAsync(pageNumber: 1, pageSize: 20);

// 聚合查询
var count = await ormClient.Queryable<User>().CountAsync();
var exists = await ormClient.Queryable<User>().AnyAsync();

// 投影查询
var names = await ormClient.Queryable<User>()
    .Select(u => new { u.Id, u.Name })
    .ToListAsync();

// 流式查询(大数据量场景)
await foreach (var user in ormClient.Queryable<User>().ToAsyncEnumerable())
{
    // 逐行处理
}
批量操作
// 批量插入(高性能)
await ormClient.InsertableRange(users).ExecuteAsync();

// BulkCopy 批量导入(最高性能)
await ormClient.BulkCopy<User>().BulkInsertAsync(users);

// 批量更新
await ormClient.BulkCopy<User>().BulkUpdateAsync(users);

// 批量保存(自动判断插入/更新)
await ormClient.BulkCopy<User>().BulkMergeAsync(users);
分表操作

定义分表实体:

/// <summary>按月保存日志,物理表名后缀为 _yyyyMM。</summary>
[OrmTable(TableName = "logs", SplitType = SplitTableType.Month, SplitColumn = nameof(CreateTime))]
public class Log
{
    /// <summary>每张物理表独立生成主键。</summary>
    [OrmColumn(IsPrimaryKey = true, IsIdentity = true)]
    public long Id { get; set; }

    /// <summary>日志内容。</summary>
    [OrmColumn(IsNullable = NullableState.Nullable)]
    public string? Message { get; set; }

    /// <summary>用于决定月份,分表依据列必须为 DateTime。</summary>
    [OrmColumn(IsNullable = NullableState.Nullable)]
    public DateTime CreateTime { get; set; }
}

/// <summary>按记录数保存采样,每个物理桶最多分配 10000 条插入记录。</summary>
[OrmTable(TableName = "sensor_data", MaxRowCount = 10000)]
public class SensorData
{
    /// <summary>每张物理表独立生成主键。</summary>
    [OrmColumn(IsPrimaryKey = true, IsIdentity = true)]
    public long Id { get; set; }

    /// <summary>本次采样值。</summary>
    [OrmColumn(IsNullable = NullableState.Nullable)]
    public double Value { get; set; }
}

/// <summary>按月和记录数保存事件,物理表形如 events_202401_1。</summary>
[OrmTable(TableName = "events", 
    SplitType = SplitTableType.Month, 
    SplitColumn = nameof(EventTime),
    MaxRowCount = 50000)]
public class Event
{
    /// <summary>每张物理表独立生成主键。</summary>
    [OrmColumn(IsPrimaryKey = true, IsIdentity = true)]
    public long Id { get; set; }

    /// <summary>决定事件所属的月份。</summary>
    [OrmColumn(IsNullable = NullableState.Nullable)]
    public DateTime EventTime { get; set; }
}

分表操作示例:

通过 .Split(startTime, endTime) 查询已有物理表,省略范围则查询全部分表;范围用于筛选分表,精确到行的时间条件仍需用 Where 指定。

var startTime = DateTime.Now.AddDays(-30);
var endTime = DateTime.Now;
var list = await ormClient.Queryable<Log>()
    .Split(startTime, endTime)
    .Where(log => log.CreateTime >= startTime && log.CreateTime <= endTime)
    .ToListAsync();

实体增删改使用 .SplitTable(),更新时间分表时实体应携带原来的分表时间。行数分表按主键定位首张匹配物理表。返回单个自增标识的分表插入只接受一条实体。

await ormClient.InsertableRange(logs).SplitTable().ExecuteAsync();
await ormClient.UpdatableRange(logs).SplitTable().ExecuteAsync();
await ormClient.DeletableRange(logs).SplitTable().ExecuteAsync();

await ormClient.BulkCopy<Log>().SplitTable().BulkInsertAsync(logs);
await ormClient.BulkCopy<Log>().SplitTable().BulkUpdateAsync(logs);
await ormClient.BulkCopy<Log>().SplitTable().BulkMergeAsync(logs);
await ormClient.Savable(logs).SplitTable().ExecuteAsync();

Savable(...).SplitTable() 按实际条件键定位已有记录,更新首张匹配表,并将新增记录交给相同的容量租约。行数实体路由按物理表名的 Ordinal 升序选择首个匹配桶,查询和分页目录按表名倒序读取。修改分表时间应显式调用 MoveSplitTableAsync(original, replacement),传入原、新快照;完整主键必须相同且不能是自增键,删除与插入在同一事务内完成。条件更新通过 SetColumns 改分表时间会提前拒绝。

Where(log => log.CreateTime >= startTime && log.CreateTime < endTime) 中直接作用于时间分表列的合取比较可自动裁剪物理表,原始 WHERE 始终保留。OR、NOT、布尔比较包装、方法调用等复杂条件不推断范围,严格边界仍由数据库筛选行。

跨表 SQL 预览使用异步 ToSqlAsync(),实体、投影和聚合均返回基于实际目录的等价数据 SQL 与参数;同步 ToSql() 对跨表查询报错。预览不代表分页计数定位等全部执行命令。

var query = ormClient.Queryable<Log>().Split()
    .Where(log => log.CreateTime >= startTime);
var preview = await query.ToSqlAsync();
var firstPage = await query.ToCursorPageAsync(100);
var secondPage = firstPage.HasMore
    ? await query.ToCursorPageAsync(100, firstPage.NextCursor)
    : null;

游标分页不查询总数,按物理表名倒序、表内完整主键升序返回,每页仅多读取一行判断 HasMore。只支持完整实体、完整非空主键及参数化查询,不能混用自定义排序、投影、Distinct 或 Skip/Take。令牌属于相同逻辑表、连接配置和筛选参数;并发修改时不提供跨页快照。需要总数、页码或自定义排序时使用 ToPageListAsync()。

自动写入首次同步当前实体的物理表结构,后续热写入复用成功状态。需要主动同步列和索引时,显式调用 CodeFirst.InitTableAsync(physicalTableName, EntityInfo.GetEntityInfo<Log>());同步只撤销该表的结构缓存,保留已发放的容量租约。物理表索引名由逻辑索引名和物理表名生成,各表独立维护唯一约束。实体查询的无排序 FirstAsync() 和从起点开始的有界 Take() 直接读取所需物理表,不预先统计全部历史表;需要总数的页码查询仍执行真实计数。

空分表目录的实体、投影及聚合查询均使用空集语义,SumAsync() 等可空标量返回 null;异步 SQL 预览也能直接执行。BulkUpdateAsync() 没有匹配记录时返回 0,不开启空数据事务;新增记录分类只用于合并。维护索引时,DropIndexAsync(tableName, indexName) 核对索引的物理表归属,避免误删邻表索引;SQLite 也隔离主库与同名临时索引。

默认每次查询真实分表目录,便于看见其它连接新建的表。表结构完全由当前进程管理时,可在创建客户端时设置 ConnectionConfig.CacheSplitTableCatalog = true,减少目录查询。经 TORM 维护 API 执行的 DDL 自动失效;外部 DDL、原始 SQL 或绕过分表路由的插入后,应在写入停止时调用 ormClient.RefreshSplitTableMetadata() 刷新目录、初始化及容量状态。

默认内置行数策略在同进程、相同完整连接配置的活动客户端之间共享容量预留,客户端副本也复用状态。SQLite 按驱动规则统一 Data Source、DataSource 和 Filename 等标准别名,保留日志与同步选项,其它配置相同的文件客户端共享容量。需要跨进程容量约束时,全部写入者启用 ConnectionConfig.CoordinateSplitTableWrites = true 并通过分表路由写入:MySQL 使用会话命名锁,PostgreSQL 使用会话建议锁,SQL Server 使用会话应用锁,SQLite 文件库使用数据库旁的稳定独占锁文件。协调锁覆盖表准备、数据事务和调用方外部事务完成,锁内重新读取目录及当前容量;该模式增加协调和实时统计成本,默认关闭。SQLite 锁文件在释放句柄后保留,存在文件不表示仍被锁定,不应在其它进程运行时删除。

服务器协调模式的外部事务必须使用 ReadCommitted;MySQL 在开始外部事务前还须预建物理表和索引。SQLite 外部事务若不能立即取得协调文件锁会明确失败,调用方须回滚后重试整个事务,避免其已持有的数据库锁与另一写入者形成反向等待;无外部事务的普通写入仍可取消等待。锁取得被取消、解锁失败或事务结果未知时,由各实现库淘汰物理会话,避免携锁连接返回池。正常锁等待超时不会释放其它会话的锁。该约束只覆盖全部遵守相同策略的 ORM 写入者,不涵盖旁路 SQL、不同容量配置及外部并发 DDL;SQLite 内存库不提供跨进程共享。

自定义 IRowCountSplitTableService 必须实现 ReserveTablesAsync,一次返回完整批次的 IRowCountTableReservation。每段须有非空表名、正条数和独立租约,条数之和等于请求数;分配失败由服务回收已发额度。执行器在写入前调用 Enlist(ado),成功后以真实条数调用 Complete(affected, ado),最后调用可重复的 ReleasePending()。已开始写入的额度归事务收尾,已知回滚归还,未知结果保守保留。自定义服务自行保证并发和容量策略;ORM 不再为其逐块追加 COUNT。显式 NotifyInserted(tableName, count, ado) 仍须按数据库归属处理,不能对同一租约重复通知。

采用内置数字桶名称规则的自定义服务可声明 UsesNumericTableSuffix = true,直接从一次真实目录中筛选时间与行数混合表;公共流程依据命名契约执行,不判断服务实现类型。其它命名保留默认值 false,由服务提供物理表列表。分表修改的可空 WhereColumns 将两个空值视为同一条件键,普通更新、Savable 与原生 Bulk 使用一致的比较规则;非空主键保留直接等号比较。

PostgreSQL 目录及维护操作使用连接的 current_schema(),SQL Server 使用登录用户的默认 schema。不同 schema 使用不同连接配置;不在活动客户端上切换搜索路径或默认 schema。逻辑表名按实现库的保守规则严格匹配,SQLite 忽略大小写,其余实现精确匹配;应始终使用物理名称的实际大小写。

一次分表增删改或 Bulk 调用的各物理表数据写入共用事务。已有外部事务时由调用方提交或回滚,调用失败后应回滚该事务;提交结果未知时保守保留容量。MySQL 外部事务开始前应预建所需表、列及索引,自动准备发现结构缺失会明确报错,避免 DDL 隐式提交。自动建表在自有数据事务之前执行,失败时已建的空表可能保留。MySQL 原生 Bulk 的重复键、截断等警告通过 MySqlBulkLoadException 抛出。

分表类型说明:

SplitTableType 说明 表名后缀格式
None 不分表(默认) -
Day 按日分表 _yyyyMMdd
Week 按周分表 _yyyyMMdd(周一日期)
Month 按月分表 _yyyyMM
Quarter 按季度分表 _yyyyQn
Year 按年分表 _yyyy
事务管理
await ormClient.UseTranAsync(async () =>
{
    await ormClient.InsertableRange(addModels).ExecuteAsync().ConfigureAwait(false);
}).ConfigureAwait(false);
AOP 日志拦截
// SQL执行前日志
ormClient.Aop.OnLogExecuting = (sql, parameters) =>
{
    Console.WriteLine($"执行SQL: {sql}");
};

// SQL执行后日志
ormClient.Aop.OnLogExecuted = (sql, parameters, elapsed) =>
{
    Console.WriteLine($"SQL执行耗时: {elapsed.TotalMilliseconds}ms");
};

// 插入/更新前修改值
ormClient.Aop.OnDataExecuting = (args) =>
{
    if (args.DataExecutingType == DataExecutingType.Insert)
    {
        // 自动填充创建时间
        if (args.Entity is BaseEntity entity)
        {
            entity.CreateTime = DateTime.Now;
        }
    }
};

Release 构建会生成 NuGet 包并输出到上级 nupkgs 目录。

相关资源

许可证

本项目使用 Apache-2.0 协议。

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  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.
  • net10.0

  • net8.0

NuGet packages (4)

Showing the top 4 NuGet packages that depend on TORM.TaosData:

Package Downloads
ThingsGatewayRuntime.Application

Package Description

ThingsGatewayRuntime.Admin

Package Description

TAdmin

Package Description

TGateway.Application

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.90 0 11/1/2026
2.0.87 108 10/28/2026
2.0.86 155 10/26/2026
2.0.85 158 10/26/2026
2.0.83 157 10/23/2026
2.0.82 343 10/19/2026
2.0.81 142 10/14/2026
2.0.80 135 10/13/2026
2.0.79 137 10/12/2026
2.0.78 263 10/7/2026
2.0.77 151 9/30/2026
2.0.76 139 9/29/2026
2.0.75 245 9/23/2026
2.0.74 182 9/21/2026
2.0.73 161 9/18/2026
2.0.72 219 9/14/2026
2.0.71 323 9/2/2026
2.0.69 217 8/31/2026
2.0.68 157 8/30/2026
2.0.63 232 8/25/2026
Loading failed