本文整理 LiteOrm 常见能力最终会生成的 SQL 形态,帮助你在调试、性能分析和数据库适配时快速建立直觉。
注意:
SqlBuilder、数据库方言、分页写法和注册扩展而有所不同。var users = await userService.SearchAsync(u => u.Age >= 18 && u.UserName!.StartsWith("A"));
典型 SQL 形态:
SELECT [T0].[Id], [T0].[UserName], [T0].[Age], [T0].[DeptId], [T0].[CreateTime]
FROM [Users] [T0]
WHERE [T0].[Age] >= @0 AND [T0].[UserName] LIKE @1
using static LiteOrm.Common.Expr;
var expr = (Prop("Age") >= 18) & Prop("UserName").StartsWith("A");
var users = await userService.SearchAsync(expr);
典型 SQL 形态:
SELECT [T0].[Id], [T0].[UserName], [T0].[Age], [T0].[DeptId], [T0].[CreateTime]
FROM [Users] [T0]
WHERE [T0].[Age] >= @0 AND [T0].[UserName] LIKE @1
var page = await userService.SearchAsync(
q => q.Where(u => u.Age >= 18)
.OrderByDescending(u => u.CreateTime)
.Skip(20).Take(10)
);
典型 SQL 形态:
SELECT [T0].[Id], [T0].[UserName], [T0].[Age], [T0].[DeptId], [T0].[CreateTime]
FROM [Users] [T0]
WHERE [T0].[Age] >= @0
ORDER BY [T0].[CreateTime] DESC
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
旧数据库或自定义方言下,分页部分可能改写为 ROW_NUMBER() 包裹查询或其他数据库专属写法。
using static LiteOrm.Common.Expr;
var users = await userService.SearchAsync(
u => Exists<Department>(d => d.Id == u.DeptId && d.Name == "研发中心")
);
典型 SQL 形态:
SELECT [T0].[Id], [T0].[UserName], [T0].[Age], [T0].[DeptId], [T0].[CreateTime]
FROM [Users] [T0]
WHERE EXISTS (
SELECT 1 FROM [Departments] [T1] WHERE [T1].[Id] = [T0].[DeptId] AND [T1].[Name] = @0
)
using static LiteOrm.Common.Expr;
var expr = ExistsRelated<DepartmentView>(Prop("Name") == "研发中心");
var users = await userService.SearchAsync(expr);
典型 SQL 形态:
SELECT [T0].[Id], [T0].[UserName], [T0].[Age], [T0].[DeptId], [T0].[CreateTime]
FROM [Users] [T0]
WHERE EXISTS (
SELECT 1 FROM [Departments] [T1] WHERE [T1].[Id] = [T0].[DeptId] AND [T1].[Name] = @0
)
如果写成:
using static LiteOrm.Common.Expr;
var expr = ExistsRelated<DepartmentView>(Prop("Name").StartsWith("研")).Not();
则典型 SQL 会变成 NOT EXISTS (...)。
var users = await viewService.SearchAsync(u => u.DeptName == "研发中心");
典型 SQL 形态:
SELECT [T0].[Id], [T0].[UserName], [T0].[Age], [T0].[DeptId], [T0].[CreateTime],
[T1].[Name] AS [DeptName]
FROM [Users] [T0]
LEFT JOIN [Departments] [T1] ON [T1].[Id] = [T0].[DeptId]
WHERE [T1].[Name] = @0
如果视图里继续引用 ParentDeptName,通常会继续追加一级 JOIN Departments T2 ...。
var sales = await salesService.SearchAsync(
s => s.Amount > 100,
tableArgs: new[] { "202411" }
);
典型 SQL 形态:
SELECT [T0].[Id], [T0].[ProductId], [T0].[Amount], [T0].[SaleTime]
FROM [Sales_202411] [T0]
WHERE [T0].[Amount] > @0
如果实体实现了 IArged,插入时表名后缀也会按对象上的 TableArgs 自动路由。
await userService.BatchInsertAsync(users);
典型 SQL 形态通常有两类:
INSERT INTO [Users] ([UserName], [Age], [CreateTime]) VALUES (@0, @1, @2), (@3, @4, @5), (@6, @7, @8)
当项目注册了 IBulkProvider 时,批量写入可能不会表现为上面的普通 SQL,而是通过数据库驱动原生批量接口完成,例如:
SqlBulkCopyMySqlBulkCopy这类场景更接近”驱动级批量导入”,而不是 ORM 逐条拼接 SQL。
using static LiteOrm.Common.Expr;
await userService.UpdateAsync(
Update<User>()
.Set("Age", Prop("Age") + 1)
.Where(Prop("DeptId") == 2)
);
典型 SQL 形态:
UPDATE [Users] SET [Age] = [Age] + 1 WHERE [DeptId] = @0
using static LiteOrm.Common.Expr;
var amountSum = Func("SUM", Prop("Amount"))
.Over([Prop("ProductId")], [Prop("SaleTime").Asc()]);
var selectExpr = From<SalesRecord>("202411")
.Select("Id", "ProductId", "ProductName", "Amount", "SaleTime")
.SelectMore(new SelectItemExpr(amountSum, "ProductTotal"));
var results = await salesDAO
.SearchAs<SalesWindowView>(selectExpr)
.ToListAsync();
典型 SQL 形态:
SELECT [T0].[Id], [T0].[ProductId], [T0].[ProductName], [T0].[Amount], [T0].[SaleTime],
SUM([T0].[Amount]) OVER (PARTITION BY [T0].[ProductId] ORDER BY [T0].[SaleTime] ASC) AS [ProductTotal]
FROM [Sales_202411] [T0]
窗口函数的最终 SQL 取决于你注册的函数处理器和当前数据库方言。
SessionManager.Current?.SqlStack 可获取当前会话执行的 SQL。SqlStack最多保留最后10条SQL,每次调用 Service 方法后SqlStack 会清空。