当默认数据库方言不足以覆盖目标数据库版本或特殊 SQL 行为时,可以通过自定义 SqlBuilder 扩展 LiteOrm。
SqlBuilder| 扩展点 | 作用 |
|---|---|
BuildSelectSql |
自定义查询语句的最终拼装方式。 |
RegisterFunctionSqlHandler |
注册自定义 SQL 函数翻译。 |
数据源级 RegisterSqlBuilder(...) |
将自定义方言绑定到指定数据源。 |
Oracle 11g 不支持现代 LIMIT/OFFSET 语法,可以通过继承 OracleBuilder 覆盖分页逻辑:
public class Oracle11gBuilder : OracleBuilder
{
public readonly static new Oracle11gBuilder Instance = new Oracle11gBuilder();
public override void BuildSelectSql(ref SqlValueStringBuilder subSelect, ref ValueStringBuilder result)
{
// 使用 ROW_NUMBER() OVER(...) 包装分页
}
}
完整实现可参考 自定义分页。
builder.Host.RegisterLiteOrm(options =>
{
options.RegisterSqlBuilder("LegacyOracle", Oracle11gBuilder.Instance);
});
builder.Host.RegisterLiteOrm(options =>
{
options.RegisterSqlBuilder(typeof(OracleConnection), Oracle11gBuilder.Instance);
});
// 1. 编写自定义方言
public sealed class LegacyOracleBuilder : OracleBuilder
{
public static readonly LegacyOracleBuilder Instance = new LegacyOracleBuilder();
}
// 2. 在启动阶段注册
builder.Host.RegisterLiteOrm(options =>
{
options.RegisterSqlBuilder("LegacyOracle", LegacyOracleBuilder.Instance);
});
// 3. 在配置里把实体或数据源指向对应数据库
[Table("Users", DataSource = "LegacyOracle")]
public class User
{
}
// 4. 业务层继续按统一方式查询
var users = await userService.SearchAsync(q => q.Where(u => u.Age >= 18).Skip(0).Take(20));
这个模式适合把兼容逻辑封装在基础设施层,业务代码不需要知道数据库版本差异。
using static LiteOrm.Common.Expr;
MySqlBuilder.Instance.RegisterFunctionSqlHandler("DATE_FORMAT", (ref outSql, expr, context, sqlBuilder, outputParams) =>
{
outSql.Append("DATE_FORMAT(");
Args[0].ToSql(ref outSql, context, sqlBuilder, outputParams);
outSql.Append(", ");
Args[1].ToSql(ref outSql, context, sqlBuilder, outputParams);
outSql.Append(')');
});
如果函数来自 Lambda 或成员扩展,还需要在 LambdaExprConverter 中注册对应的转换逻辑。详见 表达式扩展。