sql-server-2008 – 用于SQL Server 2008全文索引’包含’关键字
|
副标题[/!--empirenews.page--]
我认为在实现LinqToHql生成器类时我缺少一些基本的东西. 我已使用此注册使用自定义方言成功注册了SQL Server 2008包含的查询: RegisterFunction("contains",new StandardSQLFunction("contains",null));
我只有一个类要查询全文索引: public class SearchName
{
public virtual Guid Id {get; set;}
public virtual string Name {get; set;} // this is the search field
}
contains函数在HQL中正常工作: var names = Session.CreateQuery("from SearchName where contains(Name,:keywords)")
.SetString("keywords","john")
.List();
并且生成的SQL是完美的: select searchname0_.Id as Id4_,searchname0_.Name as Name4_ from Search_Name searchname0_ where contains(searchname0_.Name,'john' /* @p0 */) 下一个挑战是实现Linq到HQL生成器: public class MyLinqtoHqlGeneratorsRegistry :
DefaultLinqToHqlGeneratorsRegistry
{
public MyLinqtoHqlGeneratorsRegistry()
{
this.Merge(new ContainsGenerator());
}
}
public class ContainsGenerator : BaseHqlGeneratorForMethod
{
public ContainsGenerator()
{
SupportedMethods = new[] {
ReflectionHelper.GetMethodDefinition<SearchName>(d => d.Name.Contains(String.Empty))
};
}
public override HqlTreeNode BuildHql(MethodInfo method,System.Linq.Expressions.Expression targetObject,ReadOnlyCollection<System.Linq.Expressions.Expression> arguments,HqlTreeBuilder treeBuilder,IHqlExpressionVisitor visitor)
{
return treeBuilder.MethodCall("contains",visitor.Visit(targetObject).AsExpression(),visitor.Visit(arguments[0]).AsExpression()
);
}
}
}
调用这样的方法: var namesLinq = Session.Query<SearchName>().Where(x=> x.Name.Contains("john")).ToList();
不幸的是,这似乎没有覆盖内置的Contains方法,并且生成的SQL是错误的: select searchname0_.Id as Id4_,searchname0_.Name as Name4_
from Search_Name searchname0_
where searchname0_.Name like ('%' + 'john' /* @p0 */ + '%')
是否无法覆盖默认的Contains方法,或者我只是犯了一个愚蠢的错误? PS – 我正在使用NHibernate 3.3.1.4000 解决方法好的,我终于搞清楚了!首先,我设法从我的配置中删除了注册码: ...
.ExposeConfiguration(cfg =>
{
cfg.LinqToHqlGeneratorsRegistry<MyLinqtoHqlGeneratorsRegistry>();
...
}
其次,不要试图覆盖现有的Linq行为.我将Contains扩展方法移动到全文类. 第三,正确构建Hql树. 对于其他尝试实现SQL 2008自由文本包含搜索的人来说,这是完整的实现: public static class DialectExtensions
{
public static bool Contains(this SearchName sn,string searchString)
{
// this is just a placeholder for the method info.
// It does not otherwise matter.
return false;
}
}
public class MyLinqtoHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
public MyLinqtoHqlGeneratorsRegistry()
: base()
{
RegisterGenerator(ReflectionHelper.GetMethod(() =>
DialectExtensions.Contains(null,null)),new ContainsGenerator());
}
}
public class ContainsGenerator : BaseHqlGeneratorForMethod
{
string fullTextFieldName = "Name";
public ContainsGenerator()
: base()
{
SupportedMethods = new[] {
ReflectionHelper.GetMethodDefinition(() =>
DialectExtensions.Contains(null,null))
};
}
public override HqlTreeNode BuildHql(MethodInfo method,IHqlExpressionVisitor visitor)
{
// cannot figure out how to interrogate the model class to get an
// arbitrary field name...
// perhaps the RegisterGenerator() call above could be used to pass a
// property name to the ContainsGenerator constructor?
// in our case,we only have one full text searchable class,and its
// full-text searchable field is "Name"
HqlExpression[] args = new HqlExpression[2] {
treeBuilder.Ident(fullTextFieldName).AsExpression(),visitor.Visit(arguments[1]).AsExpression()
};
return treeBuilder.BooleanMethodCall("contains",args);
}
}
要使上述工作正常,您必须声明并使用自定义方言: public class CustomMsSql2008Dialect : NHibernate.Dialect.MsSql2008Dialect
{
public CustomMsSql2008Dialect()
{
RegisterFunction(
"contains",null)
);
}
}
然后您可以这样使用新的包含搜索: var namesLinq = Session.Query<SearchName>().Where(x => x.Contains("john")).ToList();
…而得到的SQL是完美的! (至少如果你只有一个表,你正在进行全文搜索) 编辑:更新实现支持超过一个FULLTEXT’包含’搜索每个查询. (编辑:91站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


