sql-server-2008 – 用于SQL Server 2008全文索引’包含’关键字的NHibernate LinqToHqlGenerator

前端之家收集整理的这篇文章主要介绍了sql-server-2008 – 用于SQL Server 2008全文索引’包含’关键字的NHibernate LinqToHqlGenerator前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我认为在实现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’包含’搜索每个查询.

这是修订版:

public static class DialectExtensions
    {
        public static bool FullTextContains(this string source,string pattern)
        {
            return false;
        }
    }

    public class MyLinqtoHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
    {
        public MyLinqtoHqlGeneratorsRegistry()
            : base()
        {
            RegisterGenerator(ReflectionHelper.GetMethod(() => DialectExtensions.FullTextContains(null,new FullTextContainsGenerator());
        }
    }

    public class FullTextContainsGenerator : BaseHqlGeneratorForMethod
    {
        public FullTextContainsGenerator()
        {
            SupportedMethods = new[] { ReflectionHelper.GetMethod(() => DialectExtensions.FullTextContains(null,null)) };
        }

        public override HqlTreeNode BuildHql(MethodInfo method,IHqlExpressionVisitor visitor)
        {
            HqlExpression[] args = new HqlExpression[2] { 
                visitor.Visit(arguments[0]).AsExpression(),visitor.Visit(arguments[1]).AsExpression() 
            };
            return treeBuilder.BooleanMethodCall("contains",args);
        }
    }

要使用修订版,语法略有不同:

var namesLinq = Session.Query<SearchName>().Where(x => x.Name.FullTextContains("john")).ToList();
原文链接:https://www.f2er.com/mssql/84133.html

猜你在找的MsSQL相关文章