3

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 => ................);

クエリがエラーをスローします(WITHmssql2008で句が追加されました):

クエリは「SELECT」または「SELECTDISTINCT」で始まる必要があります

[NotSupportedException:クエリは「SELECT」または「SELECTDISTINCT」で開始する必要があります] NHibernate.Dialect.MsSql2000Dialect.GetAfterSelectInsertPoint(SqlString sql)+179 NHibernate.Dialect.MsSql2000Dialect.GetLimitString(SqlString querySqlString、Int32 offset、Int32 limit)+119 NHibernate .Dialect.MsSql2005Dialect.GetLimitString(SqlString querySqlString、Int32 offset、Int32 last)+127 NHibernate.Loader.Loader.PrepareQueryCommand(QueryParameters queryParameters、Boolean scroll、ISessionImplementor session)+725 NHibernate.Loader.Loader.DoQuery(ISessionImplementor session、QueryParameters queryParameters 、ブールreturnProxies)+352 NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementorセッション、QueryParameters queryParameters、ブールreturnProxies)+114NHibernate.Loader。Loader.DoList(ISessionImplementorセッション、QueryParameters queryParameters)+205


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)これを引き起こすように見えます。幸いなことに、私はそのクエリのバインドを解除できます。

うまくいけば、それはこれを修正するでしょう。

4

7 に答える 7

4

Alkampfer のソリューションを使用してバグを修復しましたが、NHibernate ソースに直接パッチを適用するのではなく、独自の SQL ダイアレクトを作成しました。

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'");
    }
}
于 2011-12-12T04:53:18.307 に答える
3

同様の問題があり (削除SetMaxResultsも役に立ちましたが、ページングが必要でした)、次の NHibernate 構成プロパティがこのバグを引き起こしていることがわかりました。

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

GetAfterSelectInsertPointSQL コメントが SQL クエリの先頭に追加される可能性があることをメソッドが考慮していないため、これは確かにバグです。

use_sql_commentsプロパティを に設定するだけfalseで、問題はなくなります。

于 2011-01-21T15:05:50.743 に答える
2

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が「select」文字列の後に「TOPx」文字列を挿入できるようにするためだけに(先頭から6文字)...コメントなし:(

T

于 2010-10-15T14:41:20.320 に答える
2

Sandor さんが教えてくれたように、TOP 句 (GetAfterSelectInsertPoint) を挿入するクエリ内の場所を見つけるために使用されるルーチンに奇妙なバグがあるようです。nh ソースで直接修正できます (プロジェクトで使用している 2.1 バージョンに実際にパッチを適用しました。詳細はこちらで確認できます)。したがって、どうしても use_sql_comments でコメントを有効にする必要がある場合は、次のことができます:)

于 2011-07-28T12:30:04.643 に答える
2

1.2 から 3.2 にアップグレードするときに、この問題に遭遇しました (私は知っていますが、大きなジャンプですね?)。

私の場合の問題は、hql の select ステートメントの前に先行スペースがあることでした。たとえば、String hql = "select "...

SQL2005 Dialect では、これは「System.NotSupportedException: The query should start with 'SELECT'...」というメッセージでクラッシュします。

解決策は

  1. 失敗する単体テストを作成します。優れたテスト駆動開発者はそうすべきです:)
  2. 「select...」ステートメントから先頭のスペースを削除します
  3. 単体テストをビルドして実行する
于 2012-05-24T20:40:14.653 に答える
0

NHibernate バージョン 3.3 にアップグレードするときにこの問題に遭遇しましたが、別の理由で...空白です。次のような多くの SQL 文字列がありました。

var sql = @"
select col1 from MyTable";

また:

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

これらは、NHibernate が文字列を検証する前にトリミングしないため、"The query should start with 'SELECT' or 'SELECT DISTINCT'" エラーが発生しました。

これを回避するために、最初に文字列をトリミングする新しい方言を作成しました。

public class Sql2008DialectCustom : MsSql2008Dialect
{
  public override SqlString GetLimitString(SqlString queryString, SqlString offset, SqlString limit)
  {
    var trimmedQueryString = queryString.Trim();
    return base.GetLimitString(trimmedQueryString, offset, limit);
  }
}
于 2014-07-23T19:01:12.943 に答える
0

私が予測したように、非境界選択は許容できる回避策です。

削除されSetMaxResults、動作します。

于 2010-03-17T11:42:08.167 に答える