Вопрос по linq, nhibernate – Провайдер NHibernate linq

5

Где способ написать что-то вроде этого:

public class Item
{
    public DateTime Start { get; set; }
    public DateTime Finish{ get; set; }
}

Sessin.Query<Item>.Where( x => x.Start.AddHours( 3 ) > x.Finish );

Теперь я получаю исключение

[NotSupportedException: System.DateTime AddHours(Double)]

Да я использую оба Vasiliy Shiryaev
Вы используете NH3.3? и отображение по коду? Rippo

Ваш Ответ

2   ответа
7

шим сценарием в том, что NHibernate не знает, как переводитьDateTime.AddHours(double hours) метод. Но вы можете использовать HQL, чтобы написать аналогичный запрос? Очевидно нет. Стандартной функции HQL AddHours не существует. Поэтому вы должны зарегистрировать эту новую функцию. NHibernate использует диалекты для перевода между hql и специфическим для поставщика синтаксисом SQL. Чтобы сделать это, вы должны создать новый класс диалекта, производный от существующего, и переопределить метод RegisterFunctions. Но это решает только первую половину проблемы. Далее вы должны показать NHibernate, как использовать эту функцию в LINQ. Вы должны "отобразить" карту междуDateTime.AddHours(double hours) метод и ранее зарегистрированная пользовательская функция hql. NHibernate использует реестр для этой цели. Вам придется расширить реестр linq-to-hql по умолчанию.

Я покажу пример, который работал с NHibernate 3.3

Создайте новый класс диалекта (мой пример использует предопределенный MsSql2008Dialect)

    public class EnhancedMsSql2008Dialect : MsSql2008Dialect
    {
        protected override void RegisterFunctions() {
            base.RegisterFunctions();
            RegisterFunction("add_hours", new SQLFunctionTemplate(NHibernateUtil.DateTime, "dateadd(hour, ?1, ?2)"));
        }
    }

Создайте новый класс генератора LINQ-to-HQL, который знает, как переводить метод AddHours.

    using NHibernate.Linq.Functions;
    using NHibernate.Linq;
    using NHibernate.Hql.Ast;

    public class DateTimeMethodsHqlGenerator : BaseHqlGeneratorForMethod
    {
        public DateTimeMethodsHqlGenerator() {
            SupportedMethods = new[] {
                ReflectionHelper.GetMethodDefinition((DateTime x) => x.AddHours(1))
            };
        }

        public override HqlTreeNode BuildHql(System.Reflection.MethodInfo method, System.Linq.Expressions.Expression targetObject, System.Collections.ObjectModel.ReadOnlyCollection arguments, HqlTreeBuilder treeBuilder, NHibernate.Linq.Visitors.IHqlExpressionVisitor visitor) {
            return treeBuilder.MethodCall("add_hours", visitor.Visit(arguments[0]).AsExpression(), visitor.Visit(targetObject).AsExpression());
        }
    }

Расширить класс реестра LINQ-to-HQL по умолчанию

    public class EnhancedLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
    {
        public EnhancedLinqToHqlGeneratorsRegistry() : base() {
            //
            RegisterGenerator(ReflectionHelper.GetMethodDefinition((DateTime x) => x.AddHours(1)), new DateTimeMethodsHqlGenerator());
        }
    }

конфигурировать

    cfg.DataBaseIntegration(c => {
        c.Dialect<EnhancedMsSql2008Dialect>();
    });
    cfg.LinqToHqlGeneratorsRegistry<EnhancedLinqToHqlGeneratorsRegistry>();
Error: User Rate Limit Exceeded Vasiliy Shiryaev
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
5

то вы можете сделать что-то вроде этого.

ДобавитьLinqToHqlGeneratorsRegistry к конфигурации: -

        var configure = new Configuration()
            .DataBaseIntegration(x => {
                x.Dialect<CustomDialect>();
                x.ConnectionStringName = "db";
             })
            .LinqToHqlGeneratorsRegistry<MyLinqtoHqlGeneratorsRegistry()
            .CurrentSessionContext<WebSessionContext>();

и добавьте следующие три класса:

public class MyLinqtoHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
    public MyLinqtoHqlGeneratorsRegistry()
    {
        this.Merge(new AddHoursGenerator());
    }
}

public class AddHoursGenerator : BaseHqlGeneratorForMethod
{
    public AddHoursGenerator()
    {
        SupportedMethods = new[] {
        ReflectionHelper.GetMethodDefinition<DateTime?>(d =>      
                d.Value.AddHours((double)0))
          };
    }

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

public class CustomDialect : MsSql2008Dialect
{
    public CustomDialect()
    {
        RegisterFunction(
             "AddHours",
             new SQLFunctionTemplate(
                  NHibernateUtil.DateTime,
                  "dateadd(hh,?2,?1)"
                  )
             );
    }
}

Я основал это на этомСообщение блога Фабио.

Теперь вы можете использовать свой код как есть: -

Session.Query<Item>.Where( x => x.Start.AddHours( 3 ) > x.Finish );

Это также возможно в 3.2, ноpublic override HqlTreeNode BuildHql(..) параметры немного отличаются ...

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Vasiliy Shiryaev
Error: User Rate Limit ExceededAddHours(-4)

Похожие вопросы