mardi 4 août 2015

How to implement AddDays function in Custom SQLite Dialect for NHibernate

Please help if you can.

I am using NHibernate to connect to a Sql Server instance and all is well. For my test application (integration tests), I need to use SQLite. All of my tests are working except those which use DateTime.AddDays(n) to derive a date (DateTime) as part of the query.

For Sql Server, I have extended the MsSql2008Dialect and call

public class CustomMsSql2008Dialect : MsSql2008Dialect
{
    public CustomMsSql2008Dialect()
    {
        RegisterFunction( "AddDays", new SQLFunctionTemplate( NHibernateUtil.DateTime, "DATEADD(day,?2,?1)" ) );
    }
}

and configure this with

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
        <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
        <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
        <property name="dialect">«namespace redacted».CustomMsSql2008Dialect, «assembly name redacted»</property>
        ...
    </session-factory>
</hibernate-configuration>

and I think this works for the queries I've tested manually. I have also created the required HQLGenerator

public class AddDaysGenerator : BaseHqlGeneratorForMethod
{
    public AddDaysGenerator()
    {
        SupportedMethods = new[] {
            ReflectionHelper.GetMethodDefinition<DateTime>(d => d.AddDays(0)),
        };
    }

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

and registered same with

public class ExtendedLinqtoHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
    public ExtendedLinqtoHqlGeneratorsRegistry() : base()
    {
        this.Merge( new AddDaysGenerator() );
    }
}

I have tried to extend this to SQLite however with the following class:

public class CustomSQLiteDialect : NHibernate.Dialect.SQLiteDialect
{
    public CustomSQLiteDialect()
    {
        RegisterFunction(
            "AddDays",
            new SQLFunctionTemplate( NHibernateUtil.DateTime, "date(?1, '+' || ?2 ||' day')"
            )
        );
    }
}

and configured my test project with

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
        <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
        <property name="connection.driver_class">NHibernate.Driver.SQLite20Driver</property>
        <property name="dialect">«namespace redacted».CustomSQLiteDialect, «assembly name redacted»</property>
        ...
    </session-factory>
</hibernate-configuration>

Each test run produces

System.NotSupportedException: System.DateTime AddDays(Double)

I have many queries to test.

Is this a bug in SQLite?

Is this a bug in NHibernate?

Is this (likely) a bug in how I've implemented this?

Again, please help.

Aucun commentaire:

Enregistrer un commentaire