NHibernate 2-й уровень кеша, пользовательский запрос, sqldialect - PullRequest
3 голосов
/ 17 марта 2010

Я получил багажную версию NH и FNH.Когда я пытаюсь добавить кэш 2-го уровня, некоторые части NHibernate забывают о выбранном sqldialect.


Начальная конфигурация:

var cfg = Fluently.Configure()
  .Database(MsSqlConfiguration.MsSql2008
    .ConnectionString(connectionString)
    .DefaultSchema("dbo")
    .UseReflectionOptimizer()    
  .Mappings(m => ................);

Виновный пользовательский запрос:

var sql = @"with Foo(col1,col2,col3)
              as (select bla bla bla...)
            Select bla bla bla from Foo";

list = Session.CreateSQLQuery(sql)
  .AddEntity("fizz", typeof(Fizz))
  .SomethingUnimportant();

Когда я изменяю конфигурацию на:

var cfg = Fluently.Configure()
  .Database(MsSqlConfiguration.MsSql2008
    .ConnectionString(connectionString)
    .DefaultSchema("dbo")
     .UseReflectionOptimizer()
     .Cache(c=>c
       .UseQueryCache()
         .ProviderClass<HashtableCacheProvider>())
       .ShowSql())
     .Mappings(m => ................);

Ошибка выброса запроса (в mssql2008 было добавлено предложение WITH):

Запрос должен начинаться с «SELECT» или «SELECT DISTINCT '

[NotSupportedException: запрос должен начинаться с' SELECT 'или' SELECT DISTINCT '] NHibernate.Dialect.MsSql2000Dialect.GetAfterSelectInsertPoint (SqlString sql) +179 NHibernate.Dialect.MsSitStiaSqringSlringLDLRQСмещение Int32, ограничение Int32) +119 NHibernate.Dialect.MsSql2005Dialect.GetLimitString (SqlString querySqlString, Int32 смещение, Int32 последнее) +127 NHibernate.Loader.Loader.PrepareQueryCommand (QueryParameters queryParameters, sessionlemple).Loader.DoQuery (сеанс ISessionImplementor, QueryParameters queryParameters, Boolean returnProxies) +352 NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections (сеанс ISessionImplementor, QueryParameters queryParameters, логическое returnProxies) +114 NHibernate.Loader.Loader.1022 * Есть идеи, что именно смущает nhibernate и как его исправить?


Виновный код NHibernate (в NHibernate / Dialect / MsSql200Dialect.cs):

private static int GetAfterSelectInsertPoint(SqlString sql)
{
  if (sql.StartsWithCaseInsensitive("select distinct"))
  {
    return 15;
  }
  else if (sql.StartsWithCaseInsensitive("select"))
  {
    return 6;
  }
  throw new NotSupportedException
    ("The query should start with 'SELECT' or 'SELECT DISTINCT'");
  }
}

Видит, что .SetMaxResults(123) вызывает это.К счастью, я могу отменить этот запрос.

Надеюсь, это исправит это.

Ответы [ 7 ]

4 голосов
/ 12 декабря 2011

Я исправил ошибку, используя решение Alkampfer, но я создал свой собственный диалект SQL вместо непосредственного исправления источника NHibernate:

public class Sql2008DialectWithBugFixes : MsSql2008Dialect
{
    public override SqlString GetLimitString(SqlString querySqlString, int offset, int last)
    {
        if (offset == 0)
        {
            return querySqlString.Insert(GetAfterSelectInsertPoint(querySqlString), " top " + last);
        }

        return base.GetLimitString(querySqlString, offset, last);
    }

    private static int GetAfterSelectInsertPoint(SqlString sql)
    {
        Int32 selectPosition;

        if ((selectPosition = sql.IndexOfCaseInsensitive("select distinct")) >= 0)
        {
            return selectPosition + 15; // "select distinct".Length;

        }
        if ((selectPosition = sql.IndexOfCaseInsensitive("select")) >= 0)
        {
            return selectPosition + 6; // "select".Length;
        }

        throw new NotSupportedException("The query should start with 'SELECT' or 'SELECT DISTINCT'");
    }
}
3 голосов
/ 21 января 2011

У меня была похожая проблема (удаление SetMaxResults также помогло, но я нуждался в подкачке страниц) и обнаружило, что следующее свойство конфигурации NHibernate вызывает эту ошибку:

<property name="use_sql_comments">true</property>

Это, безусловно, ошибка, потому что метод GetAfterSelectInsertPoint не учитывает возможность добавления комментариев SQL к запросу SQL.

Просто установите для свойства use_sql_comments значение false, и проблема исчезнет.

2 голосов
/ 25 мая 2012

Я столкнулся с этой проблемой при обновлении с 1.2 до 3.2 (я знаю, БОЛЬШОЙ прыжок, а?).

Проблема в моем случае заключалась в том, что перед оператором select в hql стоит пробел, например, String hql = "select" ...

При использовании SQL2005 Dialect происходит сбой с сообщением «System.NotSupportedException: запрос должен начинаться с сообщения« SELECT »...».

Решение для

  1. создать модульный тест, который не проходит, хороший тест-ориентированный разработчик следует:)
  2. удалить начальный пробел из оператора "select ..."
  3. сборка и запуск модульного теста
2 голосов
/ 28 июля 2011

Кажется, что есть некоторая странная ошибка в подпрограмме, используемой для поиска места в запросе для вставки предложения TOP (GetAfterSelectInsertPoint), как сказал Сандор. Вы можете исправить это непосредственно в nh source (я на самом деле исправил версию 2.1, которую я использую в проекте, вы можете найти подробности здесь ). Поэтому, если вам абсолютно необходимо включить комментарии с помощью use_sql_comments, вы можете:)

2 голосов
/ 15 октября 2010

Только что возникла та же проблема при использовании аналогичного запроса с предложением WITH.

К сожалению, мой запрос заполняет таблицу сеткой, поэтому я должен сохранить SetMaxResults.

Мое решение было переписать с использованием производной таблицы:

var sql = @"with Foo(col1,col2,col3)
              as (select x1, x2, x3 from x join y blabla)
            Select col1, col2, col3 from Foo
            join B on B.col1 = Foo.col1";

становится

var sql = @"Select col1, col2, col3 from 
           (select x1 as col1, x2 as col2, x3 as col3 
            from x join y blabla) as Foo
           join B on B.col1 = Foo.col1";

Просто чтобы позволить NHibernate вставить строку "TOP x" после строки "select" (6 символов с начала) ... Без комментариев: (

T * 1013

0 голосов
/ 23 июля 2014

Мы столкнулись с этой проблемой при обновлении до NHibernate версии 3.3, но по другой причине ... пробелы. У нас было много строк sql, которые выглядели так:

var sql = @"
select col1 from MyTable";

или

var sql = @" select col1 from My Table";

Это привело к ошибкам «Запрос должен начинаться с« SELECT »или« SELECT DISTINCT »», поскольку NHibernate не обрезает строку перед ее проверкой.

Мы создали новый диалект, который сначала обрезает строку, чтобы обойти это:

public class Sql2008DialectCustom : MsSql2008Dialect
{
  public override SqlString GetLimitString(SqlString queryString, SqlString offset, SqlString limit)
  {
    var trimmedQueryString = queryString.Trim();
    return base.GetLimitString(trimmedQueryString, offset, limit);
  }
}
0 голосов
/ 17 марта 2010

Так же, как я и предсказывал, неограниченный выбор является приемлемым обходным путем.

Удалено SetMaxResults и все работает.

...