一起谈.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

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

  BaseHqlGeneratorForProperty

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

  知道了上面的内容,相信你可以自定义一个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 provider自定义扩展机制和实现。

  参考资料

  Fabio Maulo:NHibernate LINQ provider extension

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

  希望本文对你有所帮助。

时间: 2024-10-23 08:05:42

一起谈.NET技术,NHibernate3.0剖析:Query篇之NHibernate.Linq自定义扩展的相关文章

NHibernate3.0剖析:Query篇之NHibernate.Linq自定义扩展

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

一起谈.NET技术,NHibernate3.0剖析:Query篇之NHibernate.Linq标准查询

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

一起谈.NET技术,NHibernate3.0剖析:Query篇之NHibernate.Linq增强查询

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

NHibernate3.0剖析:Query篇之NHibernate.Linq标准查询

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

NHibernate3.0剖析:Query篇之NHibernate.Linq增强查询

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

一起谈.NET技术,使用Brahma在GPU上执行LINQ

Brahma是一个用于并行计算的开源库,它由C#编写并支持在多种处理器上运行.目前,Brahma仅包含一个图形处理器(GPU)模块,但是它的模块化结构可以支持更多种类的处理器.使用Brahma,同一个C#方法中的语句可以同时运行在CPU和GPU上,而不需要额外的代码. Brahma通过将LINQ语句转换成目标处理器代码来执行并行计算,所生成的代码会跟据目标处理器的不同而不同.例如针对DirectX会生成High Level Shading Language,而针对OpenGL则会生成OpenGL

一起谈.NET技术,提供第三种代码生成方式——通过自定义BuildProvider为ASP.NET提供代码生成

之前写了一些关于代码生成的文章,提供了两种不同方式的代码生成解决方案,即CodeDOM+Custom Tool和T4.对于ASP.NET应用,你还有第三种选择--自定义BuildProvider.[文中涉及的源代码从这里下载] 目录 一.BuildProvider是什么? 二.将XML表示的消息转换成VB.NET或者C#代码 三.将XML转换成CodeDOM 四.自定义BuildProvider 五.BuildProvider的应用 一.BuildProvider是什么? 对于ASP.NET应用

一起谈.NET技术,ASP.NET MVC 2 验证消息本地化策略扩展

ASP.NET MVC2 结合System.ComponentModel.DataAnnotations 提供了一套非常有效的实体验证框架.对于错误信息的处理,它默认提供了两种选择: 字符串常量 从程序集资源文件读取 但是在我们这里,我们有一套自己的资源文件方案,也就是我们需要自己控件错误信息的本地化操作.由于在元数据,我们只能提供常量,无法进行字符串操作.一种比较直接和麻烦的办法就是重写所有的验证规则,在验证规则中对字符串常量进行本地化操作. [AttributeUsage(Attribute

一起谈.NET技术,提高效率 用好Visual Studio 2010自定义代码段

我在演讲时发现这个功能也相当有用,不用现场敲代码,直接调出非常方便.Visual Studio 2010增强了自定义代码段功能,使创建自定义代码段的操作更加简单了. 有两种类型的代码段: ◆在游标中插入的Expansion自定义代码段 ◆围绕选定代码的SurroundsWith自定义代码段 创建自定义代码段 首先在项目中插入一个新的XML文件,取名为TryCatchFinally.snippet,注意文件名的后缀是.snippet,然后在编辑器窗口点击右键,选择"插入代码段"*&quo