NHibernate适配Oracle全文索引Containing关键字的LinqToHqlGenerator实现
NHibernate Oracle 全文检索语法适配方案
你需要将原有直接返回布尔方法调用的逻辑,调整为构造contains函数调用后与常量0做大于比较,最终生成符合Oracle要求的语法格式,修改后的代码如下:
public override HqlTreeNode BuildHql(MethodInfo method, System.Linq.Expressions.Expression targetObject, ReadOnlyCollection<System.Linq.Expressions.Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) { HqlExpression[] args = new HqlExpression[2] { visitor.Visit(arguments[0]).AsExpression(), visitor.Visit(arguments[1]).AsExpression() }; // 构造contains函数调用 var containsCall = treeBuilder.MethodCall("contains", args); // 构造数值0的常量表达式 var zeroConstant = treeBuilder.Constant(0); // 拼接>0的判断逻辑 return treeBuilder.GreaterThan(containsCall, zeroConstant); }
如果需要同时兼容Sql Server和Oracle两个数据源,可以增加方言类型判断,自动适配不同数据库的语法,兼容版实现如下:
using NHibernate.Dialect; public override HqlTreeNode BuildHql(MethodInfo method, System.Linq.Expressions.Expression targetObject, ReadOnlyCollection<System.Linq.Expressions.Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) { HqlExpression[] args = new HqlExpression[2] { visitor.Visit(arguments[0]).AsExpression(), visitor.Visit(arguments[1]).AsExpression() }; // 获取当前会话使用的数据库方言 var dialect = visitor.SessionFactory.GetDialect(); // Oracle场景走特殊适配逻辑 if (dialect is Oracle9iDialect or Oracle10gDialect or Oracle12cDialect) { var containsCall = treeBuilder.MethodCall("contains", args); var zeroConstant = treeBuilder.Constant(0); return treeBuilder.GreaterThan(containsCall, zeroConstant); } // Sql Server场景走原有逻辑 return treeBuilder.BooleanMethodCall("contains", args); }
实现逻辑说明:
- Sql Server中
contains是布尔类型返回值,直接用BooleanMethodCall构造即可符合语法要求 - Oracle中
contains返回数值类型的匹配得分,得分大于0表示匹配成功,因此需要先构造普通函数调用,再通过GreaterThan方法拼接大于0的判断逻辑,最终生成的SQL会自动适配为Contains("a", "b")>0的格式
内容的提问来源于stack exchange,提问作者lunatic84
相关产品推荐
相关产品推荐

