Question

Je suis version trunk de NH et FNH. Quand je tente d'ajouter 2 cache de niveau, certaines parties de NHibernate oublie SQLDIALECT choisi.


Configuration initiale:

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

Guilty requête personnalisée:

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

Quand je change la configuration à:

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

Requête jette erreur (clause WITH a été ajouté à mssql2008):

  

La requête doit commencer par 'SELECT' ou 'SELECT DISTINCT'

     

[NotSupportedException: La requête doit commencer par 'SELECT' ou 'SELECT DISTINCT']      NHibernate.Dialect.MsSql2000Dialect.GetAfterSelectInsertPoint (SqlString SQL) 179      NHibernate.Dialect.MsSql2000Dialect.GetLimitString (SqlString querySqlString, Int32 offset, limite Int32) 119      NHibernate.Dialect.MsSql2005Dialect.GetLimitString (SqlString querySqlString, Int32 offset, Int32 dernier) 127      NHibernate.Loader.Loader.PrepareQueryCommand (QueryParameters queryParameters, faites défiler booléenne, la session ISessionImplementor) +725      NHibernate.Loader.Loader.DoQuery (session ISessionImplementor, QueryParameters queryParameters, returnProxies booléennes) +352      NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections (session ISessionImplementor, QueryParameters queryParameters, returnProxies booléennes) +114      NHibernate.Loader.Loader.DoList (séance ISessionImplementor, QueryParameters queryParameters) +205


Toutes les idées que confond exactement NHibernate et comment y remédier?


Code coupable NHibernate (en NHibernate / dialecte / 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'");
  }
}

Attend qui provoque ce .SetMaxResults(123). Heureusement, je peux Unbound cette requête.

Il faut espérer que corrigera cela.

Était-ce utile?

La solution

J'ai eu un problème similaire (suppression SetMaxResults a également aidé mais je avais besoin radiomessagerie) et a trouvé que la propriété de configuration NHibernate suivante a été l'origine de ce bogue:

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

Il est certainement un bug, car la méthode GetAfterSelectInsertPoint ne prend pas en compte le fait que SQL commentaires peuvent être à la requête préfixés SQL.

Il suffit de définir la propriété use_sql_comments à false et le problème disparaît.

Autres conseils

Je réparé le bug en utilisant la solution de Alkampfer, mais je créé mon propre dialecte SQL plutôt que de modifier la source NHibernate directement:

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

Juste eu le même problème en utilisant une requête similaire qui a une clause WITH.

Malheureusement, ma requête Remplit une grille, avec la pagination, donc je dois garder setMaxResults.

Ma solution était de réécrire en utilisant une table dérivée:

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

devient

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

Juste pour permettre NHibernate d'insérer la chaîne "TOP x" après la "select" string (6 caractères du début) ... Aucun commentaire: (

T

Il semble qu'il y ait un bug étrange dans la routine utilisée pour trouver l'endroit dans la requête pour insérer la clause TOP (GetAfterSelectInsertPoint) racontée par Sandor. Vous pouvez le fixer directement dans la source nh (En fait, je patché version 2.1 J'utilise dans un projet, vous pouvez voici les détails ). Donc, si vous absolument besoin pour activer les commentaires avec use_sql_comments vous pouvez:)

J'ai rencontré ce problème lors de la mise à niveau de 1,2 à 3,2 (je sais, sauter BIG hein?).

La question dans mon cas était qu'il ya un espace de premier plan en face de l'instruction select dans la hql, par exemple Chaîne hql = "select" ...

Avec SQL2005 dialect se plante avec un "System.NotSupportedException: La requête doit commencer par 'SELECT' ...". Message

La solution est de

  1. créer un test unitaire qui échoue, un bon développeur Test Driven devrait:)
  2. supprimer l'espace principal de l'instruction "select ..."
  3. construire et exécuter le test unitaire

Tout comme prédit i - sans borne de sélection est acceptable solution

.

supprimé SetMaxResults et il fonctionne.

Nous avons rencontré ce problème lors de la mise à niveau à la version 3.3 NHibernate, mais pour une autre raison ... des espaces. Nous avons eu beaucoup de chaînes de sql qui ressemblait à ceci:

var sql = @"
select col1 from MyTable";

ou

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

Elles ont abouti à « La requête doit commencer par « SELECT » ou « SELECT DISTINCT » » erreurs car NHibernate ne pas couper la chaîne avant de la valider.

Nous avons créé un nouveau dialecte qui borde la première chaîne pour contourner ceci:

public class Sql2008DialectCustom : MsSql2008Dialect
{
  public override SqlString GetLimitString(SqlString queryString, SqlString offset, SqlString limit)
  {
    var trimmedQueryString = queryString.Trim();
    return base.GetLimitString(trimmedQueryString, offset, limit);
  }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top