zoukankan      html  css  js  c++  java
  • 一起谈.NET技术,NHibernate3.0剖析:Query篇之NHibernate.Linq自定义扩展 狼人:

      系列引入

      NHibernate3.0剖析系列分别从Configuration篇、Mapping篇、Query篇、Session策略篇、应用篇等方面全面揭示NHibernate3.0新特性和应用及其各种应用程序的集成,基于NHibernte3.0版本。如果你还不熟悉NHibernate,可以快速阅读NHibernate之旅系列文章导航系列入门,如果你已经在用NHibernate了,那么请跟上NHibernate3.0剖析系列吧。

      概述

      NHibernate.Linq除了本身提供了标准查询运算符和NHibernate特有的两个强查询立即抓取(EagerFetching)和查询缓存(QueryCacheable),我们也可以自己定义Linq provider扩展。

      Linq provider自定义扩展机制

      在NHibernate中,几乎所有的面向对象查询语言(HQL、Criteria、QueryOver)都是可扩展的,Linq也不例外。我们可以扩展自定义LINQ-provider并将LINQ扩展方法转换为SQL。下面看看NHibernate对外提供的Linq provider扩展机制。

      ILinqToHqlGeneratorsRegistry接口

      为Hql-Generators提供统一注册接口,在Build SessionFactory的时候,NHibernate注册提供的Hql-Generators。

      LinqToHqlGeneratorsRegistryFactory注册工厂

      提供Hql-Generators注册工厂,默认注册NHibernate内置支持的NHibernate.Linq查询,譬如DateTime类型提供的属性和方法、String类型提供的属性和方法、Queryable和Enumerable提供的方法。

      可以通过Configuration的"linqtohql.generatorsregistry"配置节或者Configuration类提供的LinqToHqlGeneratorsRegistry扩展方法注册实现ILinqToHqlGeneratorsRegistry接口自定义Linq provider扩展。

      DefaultLinqToHqlGeneratorsRegistry注册类

      默认NHibernate内置支持的NHibernate.Linq查询注册类,继承ILinqToHqlGeneratorsRegistry接口。

      三种Hql-Generators接口:

      IRuntimeMethodHqlGenerator

      对运行时方法注册,ICollection<T>集合的Contains方法,带LinqExtensionMethodAttribute的扩展方法。

      IHqlGeneratorForMethod

      对方法Hql生成,譬如Queryable和Enumerable类的Any、All、Min、Max、Contains方法;string类型的StartsWith、EndsWith、Contains、Equals、ToLower、ToLowerInvariant、ToUpper、ToUpperInvariant、Substring、IndexOf、Replace方法和带LinqExtensionMethodAttribute的扩展方法,NHibernate内部用于识别和转换Visitors类的方法。

      IHqlGeneratorForProperty

      对属性Hql生成,譬如DateTime类型的Year、Month、Day、Hour、Minute、Second、Date属性;string类型的Length属性。NHibernate内部用于识别和转换Visitors类的属性。

      两种Hql-Generators抽象类:

      BaseHqlGeneratorForMethod

    Linq-BaseHqlGeneratorForMethod

      BaseHqlGeneratorForMethod抽象类实现IHqlGeneratorForMethod接口。用于定义方法的Hql-Generators。例如NHibernate内置提供string类型StartWith()方法的Hql-Generators实现:

    Linq-StartsWithGenerator  BaseHqlGeneratorForProperty

    Linq-BaseHqlGeneratorForProperty  BaseHqlGeneratorForProperty抽象类实现IHqlGeneratorForProperty接口。用于定义属性的Hql-Generators。例如NHibernate内置提供string类型Length属性的Hql-Generators实现:

    Linq-LengthGenerator  知道了上面的内容,相信你可以自定义一个Linq provider扩展了。

      Linq provider自定义扩展实现

      我们以String类型为例,使用IsLike扩展方法对String类型扩展,模仿SQL中的LIKE从句。

      1.Linq扩展方法

      使用IsLike扩展方法对String类型扩展,代码如下:

    //Code Snippets Copyright http://lyj.cnblogs.com/
    public static class MyLinqExtensions
    {
    public static bool IsLike(this string source, string pattern)
    {
    pattern = Regex.Escape(pattern);
    pattern = pattern.Replace("%", ".*?").Replace("_", ".");
    pattern = pattern.Replace(@"\[", "[").Replace(@"\]","]").Replace(@"\^", "^");
    return Regex.IsMatch(source, pattern);
    }
    }

      2.IsLike扩展方法的Hql-Generators实现

      创建完扩展方法之后,就可以在内存中使用这个扩展了。但是我们需要NHibernate把他翻译成持久化查询(persistence-queries),即需要转换为SQL。像NHibernate内置的实现类似,我们需要创建一个Generators:

    //Code Snippets Copyright http://lyj.cnblogs.com/
    public class IsLikeGenerator : BaseHqlGeneratorForMethod
    {
    public IsLikeGenerator()
    {
    SupportedMethods = new[]
    {ReflectionHelper.GetMethodDefinition(() => MyLinqExtensions.IsLike(null, null))};
    }

    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject,
    ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
    {
    return treeBuilder.Like(visitor.Visit(arguments[0]).AsExpression(),
    visitor.Visit(arguments[1]).AsExpression());
    }
    }

      3.注册IsLike扩展方法Hql-Generators

      我们继承默认NHibernate内置支持的NHibernate.Linq查询注册类,这样可以把我们自定义的Hql-Generators附加进去。

    //Code Snippets Copyright http://lyj.cnblogs.com/
    public class MyLinqToHqlGeneratorsRegistry: DefaultLinqToHqlGeneratorsRegistry
    {
    public MyLinqToHqlGeneratorsRegistry()
    {
    RegisterGenerator(ReflectionHelper.GetMethodDefinition(
    () => MyLinqExtensions.IsLike(null, null)),new IsLikeGenerator());
    }
    }

      4.配置自定义Linq provider扩展

      使用IsLike扩展方法去查询DB数据,我们需要配置我们自定义的LinqToHQLGeneratorsRegistry,如果使用配置文件配置,则需要使用linqtohql.generatorsregistry:

      如果使用Loquacious-configuration就是这样:

    //Code Snippets Copyright http://lyj.cnblogs.com/
    configuration.LinqToHqlGeneratorsRegistry<MyLinqToHqlGeneratorsRegistry>();

      5.使用IsLike扩展方法

    //Code Snippets Copyright http://lyj.cnblogs.com/
    var users = session.Query<User>().Where(o => o.Name.IsLike("%永京%")).ToList();

      6.执行结果

    Linq-IsLikeExtensions  结语

      通过这篇文章学习了Linq provider自定义扩展机制和实现。

      参考资料

      Fabio Maulo:NHibernate LINQ provider extension

      NHibernate Jira: Add support for user-provided extensions to the Linq provider

      希望本文对你有所帮助。

  • 相关阅读:
    LeetCode OJ 112. Path Sum
    LeetCode OJ 226. Invert Binary Tree
    LeetCode OJ 100. Same Tree
    LeetCode OJ 104. Maximum Depth of Binary Tree
    LeetCode OJ 111. Minimum Depth of Binary Tree
    LeetCode OJ 110. Balanced Binary Tree
    apache-jmeter-3.1的简单压力测试使用方法(下载和安装)
    JMeter入门教程
    CentOS6(CentOS7)设置静态IP 并且 能够上网
    分享好文:分享我在阿里8年,是如何一步一步走向架构师的
  • 原文地址:https://www.cnblogs.com/waw/p/2158625.html
Copyright © 2011-2022 走看看