Domanda

Ho la versione trunk di NH e FNH.Quando provo ad aggiungere la cache di 2° livello, alcune parti di NHibernate dimenticano lo sqldialect scelto.


Configurazione iniziale:

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

Query personalizzata colpevole:

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();

Quando cambio la configurazione in:

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

La query genera un errore (WITH clausola è stata aggiunta in mssql2008):

La query deve iniziare con "SELECT" o "SELECT DISTINCT"

[NotSupportedException:La query dovrebbe iniziare con "Seleziona" o "seleziona distinto"] nhibernate.dialect.msql2000dialect.getAftersElectIserPoint (SQLString SQL) +179 NHibernate.Dialect.MSSSSSSSQL2000Dialect.getRitstring (SQLString QuerySqlsing, Int32 Offsate, Int32 Limit ++119 NhiBerNer. MSSQL2005Dialect.GetLimitstring (SQLString QuerysQlString, Offset INT32, INT32 Last) +127 NHibernate.Loader.Loader.PrepareQueryCommand (QueryParameters QueryParaMeters, Boolean Scroll, ISessionPement Session) +725 Parametri queryparameters, boolean returnproxies ) +352 nhibernate.loader.loader.DoqueryandInitializenLAzyCollections (sessione ISessionIMplement, queryParameters queryParameters, boolean ReturnProxies) +114 NHIBERNATE.Loader.Loader.Dolist (sessione ISessionImplemento, QueryParameters Quirameters) +205


Qualche idea su cosa confonde esattamente il nhibernate e come risolverlo?


Codice colpevole di NHibernate (in 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'");
  }
}

Sembra così .SetMaxResults(123) provoca questo.Fortunatamente, posso slegare quella query.

Speriamo che questo risolva il problema.

È stato utile?

Soluzione

Ho avuto un problema simile (SetMaxResults rimuovendo anche aiutato ma avevo bisogno di paging) e ho scoperto che la seguente proprietà di configurazione NHibernate stava causando questo bug:

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

E 'certamente un errore, perché il metodo GetAfterSelectInsertPoint non tiene conto del fatto che SQL commenti può essere preposto alla query SQL.

Basta impostare la proprietà use_sql_comments al false e il problema scompare.

Altri suggerimenti

Ho riparato il bug utilizzando la soluzione di Alkampfer, ma ho creato il mio dialetto SQL piuttosto che l'applicazione di patch direttamente alla fonte 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'");
    }
}

Ho appena avuto lo stesso problema utilizzando una query simile che ha una clausola WITH.

Sfortunatamente, la mia query popola una griglia, con il paging, quindi devo mantenere SetMaxResults.

La mia soluzione era riscrivere utilizzando una tabella derivata:

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";

diventa

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";

Giusto per permettere a NHibernate di inserire la stringa " TOP x " dopo la stringa "select" (6 caratteri dall'inizio)...No comment :(

T

Sembra che ci sia qualche strano bug nella routine utilizzato per trovare il posto nella query per inserire la clausola TOP (GetAfterSelectInsertPoint) come detto da Sandor. È possibile risolvere il problema direttamente in fonte NH (io in realtà patch versione 2.1 che sto utilizzando in un progetto, puoi trovare i dettagli qui ). Quindi, se si ha assolutamente bisogno di attivare i commenti con use_sql_comments è possibile:)

ho incontrato questo problema durante l'aggiornamento 1,2-3,2 (lo so, salto BIG eh?).

Il problema nel mio caso è stato che ci sia uno spazio di primo piano di fronte alla dichiarazione prescelta nel HQL, per esempio String HQL = "select" ...

Con SQL2005 dialetto, questo si blocca con un "System.NotSupportedException: La query deve iniziare con 'SELECT' ...". Messaggio

La soluzione è quella di

  1. creare uno unit test che non riesce, un buon sviluppatore Test Driven dovrebbe:)
  2. rimuovere lo spazio che porta dalla dichiarazione "select ..."
  3. creare ed eseguire il test di unità

Proprio come avevo previsto - unbounding select è soluzione accettabile

.

soppresso SetMaxResults e funziona.

Ci siamo imbattuti in questo problema quando l'aggiornamento alla versione 3.3 NHibernate, ma per un motivo diverso ... gli spazi bianchi. Abbiamo avuto un sacco di stringhe SQL che si presentava così:

var sql = @"
select col1 from MyTable";

o

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

Questi portato alla "La query dovrebbe iniziare con 'SELECT' o 'SELECT DISTINCT'" errori perché NHibernate non tagliare la corda prima di convalidarlo.

Abbiamo creato un nuovo dialetto che rifila la stringa prima per aggirare il problema:

public class Sql2008DialectCustom : MsSql2008Dialect
{
  public override SqlString GetLimitString(SqlString queryString, SqlString offset, SqlString limit)
  {
    var trimmedQueryString = queryString.Trim();
    return base.GetLimitString(trimmedQueryString, offset, limit);
  }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top