2010-03-17 35 views
3

我得到了NH和FNH的主幹版本。當我嘗試添加二級緩存時,NHibernate的某些部分會忘記所選的sqldialect。NHibernate 2nd lvl緩存,自定義查詢,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 => ................); 

查詢拋出錯誤(WITH條款是ADDE在mssql2008 d):

查詢應用啓動 'SELECT' 或 'SELECT DISTINCT'

[NotSupportedException異常:查詢應與 'SELECT' 或 'SELECT DISTINCT' 開始] NHibernate.Dialect。 MsSql2000Dialect.GetAfterSelectInsertPoint(SQL的SqlString)+179 NHibernate.Dialect.MsSql2000Dialect.GetLimitString(的SqlString querySqlString,偏移的Int32,的Int32限制)+119 NHibernate.Dialect.MsSql2005Dialect.GetLimitString(的SqlString querySqlString,偏移的Int32,最後的Int32)+127 NHibernate.Loader.Loader.PrepareQueryCommand(QueryParameters queryParameters,Boolean scroll,ISessionImplemen TOR會話)725 NHibernate.Loader.Loader.DoQuery(ISessionImplementor會話,QueryParameters queryParameters,布爾returnProxies)352個 NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor會話,QueryParameters queryParameters,布爾returnProxies)114 NHibernate.Loader。 Loader.DoList(ISessionImplementor會議,QueryParameters queryParameters)+205


任何想法究竟混淆NHibernate和如何解決它?


有罪NHibernate的代碼(在NHibernate的/方言/ 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)此。幸運的是,我可以解除該查詢。

希望能解決這個問題。

回答

3

我有一個類似的我ssue(除去SetMaxResults也有幫助,但我需要分頁),並發現以下NHibernate的配置屬性會造成這個錯誤:

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

這當然是一個錯誤,因爲GetAfterSelectInsertPoint方法沒有考慮到,SQL註釋賬戶可能被添加到SQL查詢中。

只需將use_sql_comments屬性設置爲false,問題就會消失。

+0

呸!被這個也抓住了。 – TWith2Sugars 2012-01-13 15:36:58

+0

不能相信它發生了! – TWith2Sugars 2012-02-16 11:18:04

0

就像我預測的那樣 - unbounding select是可以接受的解決方法。

刪除SetMaxResults它的工作原理。

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的以 「選擇」 的字符串後插入 「TOP x」 的字符串6個字符(從開始)...無評論:(

T

2

似乎在例程中有一些奇怪的錯誤,用於在查詢中找到插入TOPor子句(GetAfterSelectInsertPoint)的位置,正如Sandor所述。你可以直接在nh源代碼中修復它(我實際上修補了我在項目中使用的2.1版本,你可以使用find details here)。所以,如果你絕對需要能夠與use_sql_comments評論,你可以:)

4

我修復使用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'"); 
    } 
} 
2

我遇到從1.2升級到3.2時出現這個問題(我知道,BIG jump eh?)。

我的問題是在hql的select語句之前有一個前導空格,例如,字符串hql =「選擇」...

與SQL2005方言,這崩潰與「System.NotSupportedException:查詢應該以'SELECT'...」消息開始。

的解決方案是

  1. 創建單元測試失敗,一個好的測試驅動開發 應該:)
  2. 從「選擇...」語句
  3. 構建刪除前導空間並運行單元測試
0

我們在升級到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); 
    } 
}