为了利用MariaDB 10上的全文索引,我需要在sql字符串中使用这种新的"MATCH ANTIFY"语法。
http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html#function_match
我认为,如果仅针对某些列,我可以将linq重写为nhibernate,以更改它在使用时生成的sql,那将非常酷
.Where(x => FullTextIndexedStringProperty.Contains("Some word")).ToList().
谁能给我一些如何开始的大致指导?
这将为您提供一个非常简单的MATCH ... AGAINST
子句。如果你想变得更复杂(更多的参数,指定搜索修饰符),你必须做出一些更大的改变。希望这能让你开始:
-
创建一个新方言并注册一个简单的
MATCH (...) AGAINST (...)
函数:public class CustomMySQLDialect : MySQLDialect { public CustomMySQLDialect() { this.RegisterFunction( "matchagainst", new SQLFunctionTemplate( NHibernateUtil.Boolean, "match (?1) against (?2)")); } }
-
在
string
上创建一个静态扩展方法,用于LINQ语句:public static class LinqExtensions { public static bool MatchAgainst(this string source, string against) { throw new NotImplementedException(); } }
-
创建一个新的LINQ到HQL生成器类,将该方法与我们在自定义方言中注册的SQL函数相关联:
public class MatchAgainstGenerator : BaseHqlGeneratorForMethod { public MatchAgainstGenerator() { this.SupportedMethods = new[] { ReflectionHelper.GetMethod(() => LinqExtensions.MatchAgainst(null, null)) }; } public override HqlTreeNode BuildHql( MethodInfo method, System.Linq.Expressions.Expression targetObject, ReadOnlyCollection<System.Linq.Expressions.Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) { return treeBuilder.BooleanMethodCall( "matchagainst", arguments.Select(visitor.Visit).Cast<HqlExpression>()); } }
-
创建自定义LinqToHqlGeneratorRegistry:
public class MyLinqToHqlRegistry : DefaultLinqToHqlGeneratorsRegistry { public MyLinqToHqlRegistry() { var generator = new MatchAgainstGenerator(); RegisterGenerator(typeof(LinqExtensions).GetMethod("MatchAgainst"), generator); } }
-
在cfg.xml文件或代码中使用您的自定义方言和Linq到HQL注册表
var cfg = new Configuration() .DataBaseIntegration(db => { db.Dialect<CustomMySQLDialect>(); }) .LinqToHqlGeneratorsRegistry<MyLinqToHqlRegistry>();
-
最后,在LINQ到NHibernate查询中使用您的扩展方法:
session.Query<Article>() .Where(a => a.Body.MatchAgainst("configured")) .ToList() .Dump();
这将生成如下所示的SQL:
select userquery_0_.Id as Id51_, userquery_0_.Title as Title51_, userquery_0_.Body as Body51_ from articles userquery_0_ where match (userquery_0_.Body) against ('configured');
同样,如果您有更复杂的需求,这也无济于事。但希望这至少是一个好的起点。
如果有人好奇如何使这种支持更复杂的场景,我认为你会遇到以下问题:
- 将
MATCH
的自变量与AGAINST
的自变量分离 - 向NHibernate注册自定义SQL函数,该函数可以在不同位置接受任意数量的参数
- 即使在解决了上述两个问题之后,也要创建正确的HQL