Pregunta

Tengo la versión maletero de NH y HNF. Cuando intento agregar segundo nivel de caché, algunas partes de NHibernate se olvida de sqldialect elegidos.


configuración inicial:

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

consulta personalizada culpable:

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

Cuando i cambio de configuración en:

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

Consulta lanza error (se añadió cláusula WITH en MSSQL2008):

  

La consulta debe comenzar con 'SELECT' o 'SELECT DISTINCT'

     

[NotSupportedException: La consulta debe comenzar con 'SELECT' o "SELECT DISTINCT]      NHibernate.Dialect.MsSql2000Dialect.GetAfterSelectInsertPoint (sql SqlString) 179      NHibernate.Dialect.MsSql2000Dialect.GetLimitString (SqlString querySqlString, Int32 compensado, límite Int32) 119      NHibernate.Dialect.MsSql2005Dialect.GetLimitString (SqlString querySqlString, Int32 compensado, Int32 pasado) 127      NHibernate.Loader.Loader.PrepareQueryCommand (QueryParameters queryParameters, desplazamiento de Boole, sesión ISessionImplementor) 725      NHibernate.Loader.Loader.DoQuery (sesión ISessionImplementor, QueryParameters queryParameters, returnProxies booleanas) 352      NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections (sesión ISessionImplementor, QueryParameters queryParameters, returnProxies booleanas) 114      NHibernate.Loader.Loader.DoList (sesión ISessionImplementor, QueryParameters queryParameters) 205


Cualquier idea qué es exactamente lo confunde nhibernate y cómo solucionarlo?


código NHibernate Guilty (en NHibernate / dialecto / 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'");
  }
}

Parece que causa esta .SetMaxResults(123). Afortunadamente, puedo sin unir esa consulta.

Con suerte que va a arreglar esto.

¿Fue útil?

Solución

Yo tenía un problema similar (SetMaxResults retirar también ayudó pero necesitaba paginación) y descubrí que la propiedad siguiente configuración de NHibernate estaba causando este error:

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

Es ciertamente un error, ya que el método GetAfterSelectInsertPoint no tiene en cuenta que SQL comentarios pueden ser precedidas de la consulta SQL.

Sólo hay que establecer la propiedad use_sql_comments a false y el problema desaparece.

Otros consejos

reparé el error utilizando la solución de Alkampfer, pero he creado mi propio dialecto SQL en lugar de parchear la fuente NHibernate directamente:

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'");
    }
}

Sólo tenían el mismo problema al utilizar una consulta similar que tiene una cláusula WITH.

Por desgracia, mi consulta rellena una cuadrícula, con paginación, así que tengo que mantener setMaxResults.

Mi solución fue reescribir usando una tabla derivada:

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

se convierte

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

Sólo para permitir que NHibernate para insertar la cadena "top X" después de que la cadena "seleccionar" (6 caracteres desde el principio) ... Sin comentarios: (

T

Parece que hay algún extraño error en la rutina usada para encontrar el lugar en la consulta para insertar la cláusula TOP (GetAfterSelectInsertPoint) según lo dicho por Sandor. Se puede fijar directamente en la fuente de NH (que en realidad parcheado versión 2.1 que estoy usando en un proyecto, puede encontrar más detalles aquí ). Así que si usted tiene absoluta necesidad de permitir a los comentarios con use_sql_comments puede:)

Me encontré con este problema al actualizar de 1.2 a 3,2 (lo sé, salto GRANDE eh?).

El problema en mi caso fue que hay un espacio en blanco antes de la instrucción de selección en el HQL, por ejemplo, HQL String = "select" ...

Con SQL2005 dialecto, este se estrella con un "System.NotSupportedException: La consulta debe comenzar con 'SELECT' ...". Mensaje

La solución es

  1. crear una prueba de unidad que falla, un desarrollador Driven buena prueba debe:)
  2. quitar el espacio que va desde la declaración de "seleccionar ..."
  3. generar y ejecutar la prueba unitaria

Tal como predije - unbounding selecto solución es aceptable

.

Suprimido SetMaxResults y funciona.

Nos encontramos con este problema cuando se actualiza a la versión 3.3 NHibernate, pero por una razón diferente ... un espacio en blanco. Hemos tenido un montón de cadenas SQL que se parecía a esto:

var sql = @"
select col1 from MyTable";

o

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

Estos dio lugar a la "la consulta debe comenzar con 'SELECT' o" SELECT DISTINCT" errores debido a NHibernate no recorta la cadena antes de validarlo.

Hemos creado un nuevo dialecto que recorta la primera cadena de evitar esto:

public class Sql2008DialectCustom : MsSql2008Dialect
{
  public override SqlString GetLimitString(SqlString queryString, SqlString offset, SqlString limit)
  {
    var trimmedQueryString = queryString.Trim();
    return base.GetLimitString(trimmedQueryString, offset, limit);
  }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top