protected PaginationResult <TEntity> CreatePaginationResult(IQueryable <TEntity> query, IPageForm form, bool applyPagination) { var page = form.GetPage(); var skip = form.GetSkip(); var take = form.GetTake(); if (Mode == PaginationMode.SkipAndTake) { int actualSkip = 0; if (skip.HasValue) { actualSkip = skip.Value; } int actualTake = MaxTake; if (take.HasValue && take.Value < MaxTake) { actualTake = MaxTake; } return(new PaginationResult <TEntity>( actualSkip, actualTake, applyPagination ? query.Skip(actualSkip).Take(actualTake) : query)); } else { var pageSize = GetPageSize(form); int actualPage = 0; if (page.HasValue) { actualPage = page.Value; } else if (skip.HasValue) { actualPage = skip.Value / pageSize; } return(new PaginationResult <TEntity>( actualPage * pageSize, pageSize, actualPage, pageSize, applyPagination ? query.Skip(actualPage * pageSize).Take(pageSize) : query)); } }
public override PaginationResult <TEntity> ApplyPagination(IQueryable <TEntity> query, IPageForm form) { var filteringForm = form as IFilterForm; if (filteringForm == null) { throw new QuerySearchException("The IPageForm must also implement IFilterForm in order to support FtsQuerySearchProvider."); } var term = GetSearchExpression(filteringForm.GetTerm()); if (!string.IsNullOrWhiteSpace(term)) { // keep track of the untouched query var untouchedQuery = query; // apply where clause again (so we the outer query will be 'complete', and can simply replace what comes after the SELECT of the inner query) query = base.ApplyWhere(query, filteringForm); // if we are not sorting by the term, we should simply use the default mechanism bool isAlreadySorted = false; if (!form.SortByTermRank()) { isAlreadySorted = true; var result = base.ApplyPagination(query, form); query = result.Query; } // get the sql of the query (WHERE + JOIN + ORDER BY, etc.) var sql = query.ToSql(); // create a reader for our sql, and a builder to build a new query var reader = new StringReader(sql); var builder = new StringBuilder(); // variable to keep track of the alias used for the table in the outer query string usedAlias = string.Empty; // variable to keep track of whether or not the sql line we are iterating should be part of the new sql statement bool iteratingRelevantSql = false; string line = null; while ((line = reader.ReadLine()) != null) { if (line == "FROM (") { // read our base query var baseQuery = reader.ReadLine(); builder.AppendLine(baseQuery); // this line marks the start of the sub query } else if (line.StartsWith(") AS ")) { // this line marks the start of WHERE/ORDER BY/WHATEVER of the outer query usedAlias = line.Substring(5); iteratingRelevantSql = true; } else if (iteratingRelevantSql) { builder.AppendLine(line); } } // if we have NOT already appended a OFFSET/FETCH query part, do that now if (!isAlreadySorted) { // calculate fetch and offset int fetch = 0; int offset = 0; var page = form.GetPage(); var skip = form.GetSkip(); var take = form.GetTake(); if (Mode == PaginationMode.SkipAndTake) { if (skip.HasValue) { offset = skip.Value; } int actualTake = MaxTake; if (take.HasValue && take.Value < MaxTake) { fetch = MaxTake; } } else { var pageSize = GetPageSize(form); int actualPage = 0; if (page.HasValue) { actualPage = page.Value; } else if (skip.HasValue) { actualPage = skip.Value / pageSize; } offset = actualPage * pageSize; fetch = pageSize; } // we have NOT ordered sql, which means that we need to do it based on the term builder.AppendLine(CreateOrderBy(offset, fetch)); } // calculate the final sql and use it as the base on the untouched query var rawSql = builder.Replace(usedAlias, TableAlias).ToString(); // parameterize the final sql int parameterStart = rawSql.IndexOf(", N'") + 2; int parameterEnd = rawSql.IndexOf("' ) AS") + 1; string parameter = rawSql.Substring(parameterStart, parameterEnd - parameterStart); var finalSql = rawSql.Replace(parameter, "{0}"); return(CreatePaginationResult(untouchedQuery.FromSql(finalSql, term), form, false)); } else { return(base.ApplyPagination(query, form)); } }