我得到了NH和FNH的主干版本。当我尝试添加二级缓存时,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 => ................);
查询抛出错误(在mssql2008中添加了WITH
子句):
查询应以'SELECT'或'SELECT DISTINCT'
开头[NotSupportedException:查询应以'SELECT'或'SELECT DISTINCT'开头] 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,Boolean returnProxies)+352 NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session,QueryParameters queryParameters,Boolean returnProxies)+114 NHibernate.Loader.Loader.DoList(ISessionImplementor session,QueryParameters queryParameters)+205
任何想法究竟会混淆nhibernate以及如何修复它?
Guilty 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)
会导致这种情况。幸运的是,我可以解除查询。
希望这能解决这个问题。
答案 0 :(得分:4)
我使用Alkampfer的解决方案修复了这个bug,但是我创建了自己的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'");
}
}
答案 1 :(得分:3)
我有类似的问题(删除SetMaxResults
也有帮助,但我需要分页)并发现以下NHibernate配置属性导致了这个错误:
<property name="use_sql_comments">true</property>
这肯定是一个错误,因为GetAfterSelectInsertPoint
方法没有考虑SQL注释可以添加到SQL查询之前。
只需将use_sql_comments
属性设置为false
,问题就会消失。
答案 2 :(得分: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”字符串之后插入“TOP x”字符串(从开始的6个字符开始)...没有评论:(
Ť
答案 3 :(得分:2)
似乎在例程中有一些奇怪的错误用于在查询中找到插入TOP子句(GetAfterSelectInsertPoint)的位置,如Sandor所述。您可以直接在nh源中修复它(我实际上修补了我在项目中使用的2.1版本,您可以find details here)。因此,如果您绝对需要使用use_sql_comments启用注释,则可以:)
答案 4 :(得分:2)
从1.2升级到3.2时我遇到了这个问题(我知道,BIG跳了呃?)。
在我的案例中,问题是在hql中的select语句前面有一个前导空格,例如String hql =“select”...
使用SQL2005 Dialect,这会导致“System.NotSupportedException崩溃:查询应以'SELECT'...”开头。
解决方案是
答案 5 :(得分:0)
就像我预测的那样 - 无限制的选择是可接受的解决方法。
已删除SetMaxResults
并且有效。
答案 6 :(得分:0)
我们在升级到NHibernate版本3.3时遇到了这个问题,但出于不同的原因......空白。我们有很多sql字符串,如下所示:
var sql = @"
select col1 from MyTable";
或:
var sql = @" select col1 from My Table";
这导致&#34;查询应以&#39; SELECT&#39;开头。或者&#39;选择DISTINCT&#39;&#34;错误,因为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);
}
}