我正在尝试使用NHibernate创建分页复杂查询。像这样:
SELECT TOP 10 * FROM (
SELECT
ROW_COUNT() ... as 'rowNum',
Value,
(SELECT TOP 1 FROM Table1 WHERE Condition ORDER BY Column)
FROM Table2
WHERE EXISTS(SELECT null FROM Table1 WHERE Condition)
) WHERE rowNum > 10
重现问题的最简单的测试用例是:
var criteria = CurrentSession.CreateCriteria<Table>();
var subCriteria = DetachedCriteria.For<Table>()
.SetProjection(Projections.Id())
.SetMaxResults(1);
criteria.SetProjection(Projections.ProjectionList()
.Add(Projections.Constant(1))
.Add(Projections.SubQuery(subCriteria)))
.SetMaxResults(10)
.SetFirstResult(1)
.List();
不幸的是,这会产生错误的SQL - 子查询SetMaxResult所有问题。我该如何解决?
答案 0 :(得分:0)
为了克服这个错误,我不得不改写方言。它可能不是那么好和干净,但在这里。所有更改都在此方法中:
private static int GetFromIndex(SqlString querySqlString)
{
/* A large amount of modifications were made to the following code in order to work around the bug here: https://nhibernate.jira.com/browse/NH-3286*/
var queryRealString = querySqlString.ToString();
// Remove any 'TOP (?)' clauses from the query because 'GetSubselectString' doesn't handle them
var querySqlStringWithoutTops = new SqlString(queryRealString.Replace(" TOP (?)", ""));
string subselect = querySqlStringWithoutTops.GetSubselectString().ToString();
// Regex match the subselect - the original code got this part wrong too
int fromIndex = Regex.Match(querySqlStringWithoutTops.ToString(), Regex.Escape(subselect) + @"($|\s|\,|\)|\n)", RegexOptions.Multiline).Index;
// Not sure if the next bit is going to work with our changes...
if (fromIndex == -1)
{
fromIndex = queryRealString.ToLowerInvariant().IndexOf(subselect.ToLowerInvariant());
}
// Work out the length of all the 'TOP (?)' that were removed above
var currentStart = 0;
var lengthOfDeletedTops = 0;
int ixOfTops;
var topLength = " TOP (?)".Length;
while (currentStart < fromIndex
&& (ixOfTops = queryRealString.IndexOf(" TOP (?)", currentStart, fromIndex - currentStart, StringComparison.OrdinalIgnoreCase)) >= 0)
{
lengthOfDeletedTops += topLength;
currentStart = ixOfTops + topLength;
}
return fromIndex + lengthOfDeletedTops;
}