zoukankan      html  css  js  c++  java
  • NHibernate 3 Extending the Linq Provider to fix some System.NotSupportedException

    With the release of the new version NHibernate (3.0 alpha1), I’ve decided to give it a try and branch my current solution to switch to this new version and see hoe it goes.

    I was especially interested in the new Linq support, cause I’ve decided to use it as the basis for my data access strategies.

    After the necessary reference changes I run all my test suit...and I had bad news from the Linq provider in the form of some System.NotSupportedException like this one:

    “UnitTest.Test03_Linq.QueryWithEqualsGuid:
    System.NotSupportedException : Boolean Equals(System.Guid)”

    Being NHibernate an open source project, instead of bothering the guys responsible for the project, my first approach is always to look at the code; so I downloaded the trunk and started looking around at the Linq provider. Watching how Equals() methods are handled by the parser it comes out fast that only the specific version to deal with strings is currently supported [bool Equals(string)], all other types have to rely on the ==operator.

    But in my code I had a lot of filters based on Equals() call for various object types (int, guid and so on...) and I didn’t wanted to touch that code especially considering that with the previous Linq provider everything was working well.

    However the solution is easy, just extend the default EqualsGenerator adding the support for the missing methods; but I didn’t wanted to compile a specific ‘patched’ version of NHibernate and this post from Fabio Maulo confirmed me you can easily extend the Linq provider. Great! That’s was exactly what I was looking for!

    I started working on it and I had my second surprise Open-mouthed smile. The Linq provider was subhect of a heavy refactoring activity to provide better extensibility from the version you have in 3.0 alpha1. Using reflector and looking around in the binaries it comes out that to extend that provider you have to register your extension methods calling the methods of the NHibernate.Linq.Functions.FunctionRegistry class. But in all honesty I think that the way it works in alpha2 is way more elegant and it follows better the standard approach NHibernate have when it comes to configure its components.

    So if you have to extend the Linq provider forget of alpha1 and compile your own version of NHibernate getting it from the Trunk.

    Back to the job now: following Fabio’s instructions (and looking at the code) I came out with these classes:

    public class ExtendedEqualsGenerator : BaseHqlGeneratorForMethod
    {
        public ExtendedEqualsGenerator()
        {
            // the methods call are used only to get info about the signature, the actual parameter is just ignored
            SupportedMethods = new[] { 
                ReflectionHelper.GetMethodDefinition<Byte>(x => x.Equals((Byte)0)),
                ReflectionHelper.GetMethodDefinition<SByte>(x => x.Equals((SByte)0)),
                ReflectionHelper.GetMethodDefinition<Int16>(x => x.Equals((Int16)0)),
                ReflectionHelper.GetMethodDefinition<Int32>(x => x.Equals((Int32)0)),
                ReflectionHelper.GetMethodDefinition<Int64>(x => x.Equals((Int64)0)),
                ReflectionHelper.GetMethodDefinition<UInt16>(x => x.Equals((UInt16)0)),
                ReflectionHelper.GetMethodDefinition<UInt32>(x => x.Equals((UInt32)0)),
                ReflectionHelper.GetMethodDefinition<UInt64>(x => x.Equals((UInt64)0)),
                ReflectionHelper.GetMethodDefinition<Single>(x => x.Equals((Single)0)),
                ReflectionHelper.GetMethodDefinition<Double>(x => x.Equals((Double)0)),
                ReflectionHelper.GetMethodDefinition<Boolean>(x => x.Equals(true)),
                ReflectionHelper.GetMethodDefinition<Char>(x => x.Equals((Char)0)),
                ReflectionHelper.GetMethodDefinition<Decimal>(x => x.Equals((Decimal)0)),
                ReflectionHelper.GetMethodDefinition<Guid>(x => x.Equals(Guid.Empty)),
            };
        }
      
        public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
        {
            return treeBuilder.Equality(
                    visitor.Visit(targetObject).AsExpression(),
                    visitor.Visit(arguments[0]).AsExpression());
        }
    }
      
    public class ExtendedLinqtoHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
    {
        public ExtendedLinqtoHqlGeneratorsRegistry()
        {
            this.Merge(new ExtendedEqualsGenerator());
        }
    }

    After registering them (actually it can be done only in code) using:

    configuration.SetProperties("linqtohql.generatorsregistry", "Nhibernate.Extensions.ExtendedLinqtoHqlGeneratorsRegistry, Nhibernate.Extensions");
      
    or
      
    configuration.LinqToHqlGeneratorsRegistry<ExtendedLinqtoHqlGeneratorsRegistry>();

    My tests passed again and I didn’t had to touch a single line of code. This is simply amazing! (but I think the full support for all the equals methods should have been added to the core anyway).

  • 相关阅读:
    【Mac + Appium + Java1.8学习(三)】之IOS自动化环境安装配置以及简单测试用例编写(模拟器、真机)
    【Mac + Appium + Java1.8学习(一)】之Android自动化环境安装配置以及IDEA配置(附录扩展Selenium+Java自动化)
    【Mac + Appium + Python3.6学习(六)】之安装Android模拟器(Genymotion)并运行模拟器进行自动化
    【Mac + Appium + Python3.6学习(五)】之常用的Android自动化测试API总结
    【Mac + Appium + Python3.6学习(四)】之常用的IOS自动化测试API总结
    【Mac + Appium + Python3.6学习(三)】之IOS自动化测试环境配置
    【Mac + Appium + Python3.6学习(二)】之Android自动化测试,appium-desktop配置和简易自动化测试脚本
    【Mac + Appium学习(一)】之安装Appium环境前提准备
    【Mac + Python3.6 + ATX基于facebook-wda】之IOS自动化(三):facebook-wda库--API学习以及附录:Github上对WDA的问题解答
    【转】【Mysql学习】之Mac上用终端使用mySQL
  • 原文地址:https://www.cnblogs.com/aaa6818162/p/2418614.html
Copyright © 2011-2022 走看看