简体   繁体   English

用于查询和子查询的SetMaxResult

[英]SetMaxResult for query and subquery

I am trying to create complex query with paging using NHibernate. 我正在尝试使用NHibernate进行分页创建复杂的查询。 Something like this: 像这样:

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

The simplest test-case to reproduce issue is: 重现问题的最简单的测试用例是:

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();

Unfortunately, this produces wrong SQL - subqueries SetMaxResult screws all up. 不幸的是,这会产生错误的SQL-子查询SetMaxResult螺钉全部固定。 How can I fix it? 我该如何解决?

In order to overcome this bug I had to rewrite the dialect. 为了克服此错误,我不得不重写方言。 It might not be that good and clean but here it is. 它可能不是那么好干净,但是确实如此。 All the changes are inside this method: 所有更改都在此方法内部:

    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;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM