一个轻量级、高性能的 .NET ORM 框架
English | 中文
建议先从文档中心进入,再按场景查阅索引页,这样更容易建立完整的使用路径。
- 入门篇:快速完成安装、注册和第一个可运行示例
- 核心使用篇:重点阅读实体映射、Expr / 查询指南、CRUD、关联查询,以及 Lambda 与 Expr 组合使用
- 高级特性篇:集中查看事务、分表、性能、窗口函数、权限过滤和日志诊断
- 扩展开发篇:查看表达式扩展、Expr 序列化,以及前端
QueryString/ 原生Expr查询接入方案
LiteOrm 是一个轻量级、高性能的 .NET ORM 框架,兼顾微型 ORM 的执行效率和完整 ORM 的易用性,适合对性能敏感且又需要灵活处理复杂 SQL 的业务场景。
- 极速性能:性能接近原生 Dapper,远超 EF Core
- 多数据库支持:原生支持 SQL Server、MySQL、Oracle、PostgreSQL、SQLite
- 灵活查询:支持基于 Lambda、
Expr或ExprString的多种查询方式 - 自动关联:通过特性实现无损的 JOIN 查询,无需手写 SQL
- 声明式事务:
[Transaction]特性实现 AOP 事务管理 - 日志与诊断:支持
ServiceLog、Log特性及慢查询日志 - 动态分表:
IArged接口支持分表路由 - 异步支持:完整的 async/await 支持
- 类型安全:强类型泛型接口,编译时类型检查
-
.NET 8.0+ / .NET Standard 2.0(兼容 .NET Framework 4.6.1+)
-
依赖库:Autofac、Castle.Core
-
支持的数据库:SQL Server 2012+、Oracle 12c+、PostgreSQL、MySQL 8.0+、SQLite
如果目标数据库版本较旧,可能需要自定义分页,参见 自定义分页。
dotnet add package LiteOrm在 appsettings.json 中:
{
"LiteOrm": {
"Default": "DefaultConnection",
"DataSources": [
{
"Name": "DefaultConnection",
"ConnectionString": "Server=localhost;Database=TestDb;...",
"Provider": "MySqlConnector.MySqlConnection, MySqlConnector"
}
]
}
}在 Program.cs 中注册:
Console:
var host = Host.CreateDefaultBuilder(args)
.RegisterLiteOrm() // 自动初始化
.Build();ASP.NET Core:
var builder = WebApplication.CreateBuilder(args);
builder.Host.RegisterLiteOrm(); // 通过 IHostBuilder 扩展方法集成using LiteOrm.Common;
[Table("Users")]
public class User : ObjectBase
{
[Column("Id", IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
[Column("UserName")]
public string UserName { get; set; }
[Column("Email")]
public string Email { get; set; }
[Column("Age")]
public int Age { get; set; }
[Column("Status")]
public int Status { get; set; }
[Column("CreateTime")]
public DateTime? CreateTime { get; set; }
}// 定义视图模型(用于查询,可包含关联字段)
public class UserView : User { }
public interface IUserService :
IEntityService<User>, IEntityServiceAsync<User>,
IEntityViewService<UserView>, IEntityViewServiceAsync<UserView>
{
}
public class UserService : EntityService<User, UserView>, IUserService
{
}可以使用自定义服务,也可以直接注入泛型接口:
// 插入
var user = new User { UserName = "admin", Email = "admin@test.com" };
await userService.InsertAsync(user);
// 查询
var users = await userService.SearchAsync(u => u.Email.Contains("test"));
var admin = await userService.SearchOneAsync(u => u.UserName == "admin");
// 更新
user.Email = "newemail@test.com";
await userService.UpdateAsync(user);
// 删除
await userService.DeleteAsync(user);
// 分页
var page = await userService.SearchAsync(
q => q.Where(u => u.CreateTime > DateTime.Today)
.OrderByDescending(u => u.CreateTime)
.Skip(0).Take(10)
);// 基础查询
var users = await userService.SearchAsync(u => u.Age > 18);
// 排序
var sorted = await userService.SearchAsync(
q => q.Where(u => u.Age > 18).OrderBy(u => u.Age)
);
// 分页
var paged = await userService.SearchAsync(
q => q.Where(u => u.Status == 1)
.OrderBy(u => u.Id)
.Skip(10).Take(20)
);using static LiteOrm.Common.Expr;
// 手动构建表达式(支持更复杂的动态条件)
var expr = Prop("Age") > 18 & Prop("Status") == 1;
var users = await userService.SearchAsync(expr);
// IN 查询
var users = await userService.SearchAsync(
Prop("Id").In(1, 2, 3, 4, 5)
);
// LIKE 查询
var users = await userService.SearchAsync(
Prop("UserName").Contains("admin")
);
// 链式构建复杂查询
var query = From<User>()
.Where(Prop("Age") > 18)
.OrderBy(Prop("CreateTime"))
.Section(0, 10); // LIMIT/OFFSET
var result = await userService.SearchAsync(query);using static LiteOrm.Common.Expr;
// 使用参数化插值字符串,防止 SQL 注入
int minAge = 18;
var expr = Prop("Age") > 25;
// ObjectViewDAO 示例
var users = await objectViewDAO.Search($"WHERE {expr} AND Age > {minAge}").ToListAsync();
// DataViewDAO 示例
var dataTable = await dataViewDAO.Search(
$"SELECT Id, UserName FROM Users WHERE {Prop("Age")} > {minAge}",
isFull: true
).GetResultAsync();
ExprString是 DAO 查询入口,不是 Service 查询入口。它既可以像上面第一个示例那样补Search的条件片段,也可以像第二个示例这样在 DAO 中传完整 SQL。
ExprString不支持把SelectExpr.With(name)/CommonTableExpr这样的 CTE 表达式自动转成WITHSQL;如果需要 CTE,请使用Expr/SelectExpr构建,或在 DAO 层手动写完整 SQL。
ExprString中手写标识符时,可以把[、]当作通用引用符占位使用;命令真正执行前,LiteOrm 会按当前数据库方言替换成实际引用符。
LiteOrm 支持用 SelectExpr.With(name) 构建 CTE:
using static LiteOrm.Common.Expr;
var cteDef = From<User>()
.Where(Prop("Age") >= 18)
.Select(
Prop("Id").As("Id"),
Prop("UserName").As("Name"),
Prop("Age").As("Age")
);
var query = cteDef.With("AdultUsers")
.Where(Prop("Age") >= 25)
.OrderBy(Prop("Name").Asc())
.Select(Prop("Name"), Prop("Age"));
var result = await dataViewDAO.Search(query).GetResultAsync();同一个 CTE 表达式也可以在 UNION 两侧复用:
using static LiteOrm.Common.Expr;
var adultUsers = From<User>()
.Where(Prop("Age") >= 18)
.Select(
Prop("UserName").As("Name"),
Prop("Age").As("Age"))
.With("AdultUsers");
var query = adultUsers
.Where(Prop("Age") < 30)
.Select(Prop("Name"), Prop("Age"), Const("18-29").As("AgeGroup"))
.UnionAll(
adultUsers
.Where(Prop("Age") >= 30)
.Select(Prop("Name"), Prop("Age"), Const("30+").As("AgeGroup")));同别名 CTE 现在会先做校验:
- 定义相等:自动去重,只保留第一个
- 定义不相等:抛出异常
详细说明见:CTE 指南
using static LiteOrm.Common.Expr;
// 检查关联数据存在性
var result = await userService.SearchAsync(
q => q.Where(u => Exists<Order>(o => o.UserId == u.Id))
);// 定义关联
[Table("Orders")]
public class Order
{
[Column("Id", IsPrimaryKey = true)]
public int Id { get; set; }
[Column("UserId")]
[ForeignType(typeof(User))]
public int UserId { get; set; }
}
// 视图模型包含关联字段
public class OrderView : Order
{
[ForeignColumn(typeof(User), Property = "UserName")]
public string UserName { get; set; }
}
// 查询时自动 JOIN
var orders = await orderService.SearchAsync<OrderView>();public class BusinessService
{
private readonly IUserService userService;
private readonly IOrderService orderService;
[Transaction]
public async Task CreateUserWithOrder(User user, Order order)
{
await userService.InsertAsync(user);
order.UserId = user.Id;
await orderService.InsertAsync(order);
}
}[Table("Logs_{0}")] // {0} 会被 TableArgs 替换
public class Log : IArged
{
[Column("Id", IsPrimaryKey = true)]
public int Id { get; set; }
[Column("Content")]
public string Content { get; set; }
[Column("CreateTime")]
public DateTime CreateTime { get; set; }
// 自动按月份路由到 Log_202401、Log_202402 等表
string[] IArged.TableArgs => [CreateTime.ToString("yyyyMM")];
}查询时可通过 tableArgs、WithArgs(...) 或 Expr.From<T>(...) 显式指定分表参数;主表指定的 TableArgs 会传递给同作用域或下级作用域中的后续表,未显式指定时会继续沿用这组参数。若表名包含多个占位符(如 Sales_{0}_{1}),也可以分别传入 ["US", "2025"] 这样的多维参数,避免手工拼接分表名。不同表还可以错开使用不同占位符位置,例如 Table1_{0} 与 Table2_{1} 可共享同一个参数数组,让一组 TableArgs 同时驱动多张表。
基于 LiteOrm.Benchmark 项目的最新对比测试结果(.NET 10.0.4, Linux Ubuntu 24.04 LTS, Intel Xeon Silver 4314 CPU 2.40GHz, MySQL):
| 框架 | 100 条 | 1000 条 | 5000 条 |
|---|---|---|---|
| LiteOrm | 3.98 | 16.39 | 75.62 |
| SqlSugar | 4.33 | 19.12 | 98.15 |
| FreeSql | 4.36 | 18.48 | 85.00 |
| EF Core | 18.50 | 150.35 | 670.19 |
| Dapper | 26.19 | 215.12 | 1,129.57 |
| 框架 | 100 条 | 1000 条 | 5000 条 |
|---|---|---|---|
| LiteOrm | 4.84 | 25.36 | 118.70 |
| SqlSugar | 6.39 | 42.62 | 232.66 |
| FreeSql | 5.88 | 40.31 | 175.58 |
| EF Core | 17.26 | 126.44 | 575.32 |
| Dapper | 28.63 | 248.71 | 1,213.51 |
| 框架 | 100 条 | 1000 条 | 5000 条 |
|---|---|---|---|
| LiteOrm | 7.54 | 23.72 | 103.52 |
| SqlSugar | 10.36 | 106.11 | 1,741.49 |
| FreeSql | 5.53 | 19.11 | 103.06 |
| EF Core | 19.05 | 135.88 | 589.07 |
| Dapper | 29.09 | 247.51 | 1,248.91 |
| 框架 | 100 条 | 1000 条 | 5000 条 |
|---|---|---|---|
| LiteOrm | 1.36 | 9.35 | 43.94 |
| SqlSugar | 2.29 | 22.10 | 89.97 |
| FreeSql | 1.75 | 9.10 | 43.89 |
| EF Core | 4.93 | 15.62 | 55.16 |
| Dapper | 1.48 | 9.07 | 45.64 |
| 框架 | 插入 | 更新 | Upsert | 关联查询 |
|---|---|---|---|---|
| LiteOrm | 862.82 | 1,189.03 | 1,973.38 | 230.38 |
| SqlSugar | 4,573.59 | 7,679.63 | 35,952.88 | 9,228.26 |
| FreeSql | 4,667.20 | 6,917.50 | 2,256.36 | 866.52 |
| EF Core | 12,503.04 | 9,044.24 | 9,005.39 | 2,198.05 |
| Dapper | 2,476.36 | 3,093.19 | 2,798.36 | 418.43 |
📊 详细的性能基准报告请参考 LiteOrm.Benchmark
建议先阅读文档中心,再根据具体问题跳转到索引页或示例页。
| 资源 | 说明 |
|---|---|
| 文档中心 | 按学习路径组织的中英文文档导航 |
| English Docs Hub | Bilingual docs hub organized by learning path |
| API 索引 | 按使用场景整理的接口与能力入口 |
| AI 使用指南 | 面向 AI 和快速查阅场景的附录 |
| Demo 项目 | 主要特性的演示工程 |
| 性能报告 | 详细的性能基准测试报告 |
| 单元测试 | 行为与回归测试覆盖 |
如发现问题或有改进建议,欢迎提交 Issue 或 Pull Request。
基于 MIT 协议发布。