nhibernate 2nd LVL 캐시, 사용자 정의 쿼리, sqldialect
-
20-09-2019 - |
문제
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 => ................);
쿼리는 오류를 던집니다 (WITH
조항은 MSSQL2008에 추가되었습니다.
쿼리는 'select'또는 'select'로 시작해야합니다.
NotSupportedException : 쿼리는 'select'또는 'select'로 시작해야합니다.] nhibernate.dialect.mssql2000dialect.getAfterselectinsertpoint (sqlstring sql) +179 nhibernate.dialect.mssql2000dialect.msql2000dialect.mstring (sqlstring), int322222212222122212221222212. .dialect.mssql2005dialect.getlimitstring (sqlstring querysqlstring, int32 int32 int32 last) +127 nhibernate.loader.loader.preparequerycommand (QueryParameters QueryParameters, QueSeciorItors espector, issessionimplementor session). , 부울 returnProxies) +352 nhibernate.loader.loader.loader.doqueryAndinitializenonLazyCollection (issessionimplementor 세션, QueryParameters QueryParameters, Boolean returnProxies) +114 nhibernate.loader.loader.dolist (issessionimplementor session, queryameters) queryameters
Nhibernate를 정확히 혼란스럽게하는 아이디어와 그것을 고치는 방법은 무엇입니까?
유죄 Nhibernate 코드 (nhibernate/divelect/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)
이것을 원인합니다. 다행히도 해당 쿼리를 해제 할 수 있습니다.
바라건대 이것은 이것을 고칠 것입니다.
해결책
비슷한 문제가있었습니다 (제거 SetMaxResults
또한 도움이되었지만 페이징이 필요했습니다.)
<property name="use_sql_comments">true</property>
그것은 확실히 버그이기 때문입니다 GetAfterSelectInsertPoint
메소드는 SQL 댓글이 SQL 쿼리로 선정 될 수 있다는 것을 고려하지 않습니다.
그냥 설정하십시오 use_sql_comments
속성 false
그리고 문제가 사라집니다.
다른 팁
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'");
}
}
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";
becomes
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"문자열 (시작에서 6 자) 다음에 "상단 X"문자열을 삽입하도록하기 위해 ... 댓글 없음 :(
티
Sandor가 말한대로 상단 절 (getAfterselectinsertPoint)을 삽입하기 위해 쿼리에서 장소를 찾는 데 사용되는 일상에 이상한 버그가있는 것 같습니다. NH 소스에서 직접 수정할 수 있습니다 (실제로 프로젝트에서 사용중인 2.1 버전을 패치했습니다. 여기에서 세부 정보를 찾으십시오). 따라서 use_sql_comments를 사용하여 댓글을 절대적으로 활성화 해야하는 경우 :)
1.2에서 3.2로 업그레이드 할 때이 문제가 발생했습니다 (Big Jump Eh?).
내 경우의 문제는 HQL, 예를 들어 STRING HQL = "SELECT"...
SQL2005 방언을 사용하면 "System.notsupportedException : 쿼리는 'Select'... ..."메시지로 시작해야합니다.
해결책은해야합니다
- 실패한 단위 테스트를 만들고, 좋은 테스트 중심 개발자는 :)
- "Select ..."진술에서 선행 공간을 제거하십시오.
- 장치 테스트를 빌드하고 실행하십시오
내가 예측 한 것처럼 - 결합되지 않은 선택은 허용 가능한 해결 방법입니다.
삭제 SetMaxResults
그리고 그것은 작동합니다.
우리는 nhibernate 버전 3.3으로 업그레이드 할 때이 문제를 해결했지만 다른 이유가 있습니다 ... 공백. 우리는 다음과 같이 보이는 많은 SQL 문자열을 가지고있었습니다.
var sql = @"
select col1 from MyTable";
또는:
var sql = @" select col1 from My Table";
그 결과 nhibernate가 문자열을 검증하기 전에 문자열을 다듬지 않기 때문에 "쿼리는 'select'또는 'select'오류로 시작해야합니다.
우리는 이것을 먼저 줄이는 새로운 방언을 만들었습니다.
public class Sql2008DialectCustom : MsSql2008Dialect
{
public override SqlString GetLimitString(SqlString queryString, SqlString offset, SqlString limit)
{
var trimmedQueryString = queryString.Trim();
return base.GetLimitString(trimmedQueryString, offset, limit);
}
}