Example #1
0
 /// <summary>
 /// Gets the sorting to be used.
 /// </summary>
 /// <returns></returns>
 public static IEnumerable <SortMemberAccess> GetSorting(this IPageForm form, ParameterExpression parameter)
 {
     if (!string.IsNullOrWhiteSpace(form.GetOrderBy()))
     {
         return(ExpressionHelper.CalculateSortMemberAccesses(parameter, form.GetOrderBy()));
     }
     return(null);
 }
        protected int GetPageSize(IPageForm form)
        {
            switch (Mode)
            {
            case PaginationMode.PageSize:
                return(PageSize);

            case PaginationMode.PredefinedPageSizes:
                var pageSize = form.GetPageSize();
                if (!pageSize.HasValue)
                {
                    throw new QuerySearchException("No page size has been specified in the query.");
                }
                if (!PredefinedPageSizes.Contains(pageSize.Value))
                {
                    throw new QuerySearchException("The specified page size is not allowed.");
                }
                return(pageSize.Value);

            case PaginationMode.AnyPageSize:
                return(form.GetPageSize() ?? PageSize);

            case PaginationMode.MinMaxPageSize:
                var ps = form.GetPageSize();
                if (!ps.HasValue)
                {
                    throw new QuerySearchException("No page size has been specified in the query.");
                }
                if (ps < MinPageSize || ps > MaxPageSize)
                {
                    throw new QuerySearchException("Invalid page size was specified.");
                }
                return(ps.Value);

            default:
                throw new QuerySearchException($"Invalid PaginationMode configured: {Mode}.");
            }
        }
Example #3
0
        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));
            }
        }
        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));
            }
        }
        /// <summary>
        /// Applies the pagination form to the query.
        /// </summary>
        /// <param name="query">The query that should be paginated.</param>
        /// <param name="form">The pagination form that should be applied to the query.</param>
        /// <returns>A pagination result.</returns>
        public virtual PaginationResult <TEntity> ApplyPagination(IQueryable <TEntity> query, IPageForm form)
        {
            var sorting = form.GetSorting(_parameter)?.ToList();
            var alreadySortedByPropertyPaths = new List <string>();

            if (sorting != null && sorting.Count > 0)
            {
                // first order by user specified sorting

                bool isSorted = false;
                foreach (var sort in sorting)
                {
                    if (sort.MemberAccessor != null)
                    {
                        query = query.OrderBy(_parameter, sort, isSorted);
                    }
                    else
                    {
                        query = ApplyManualOrdering(query, sort.PropertyPath, sort.SortDirection, isSorted);
                    }
                    isSorted = true;

                    alreadySortedByPropertyPaths.Add(sort.PropertyPath);
                }

                query = ApplyUniqueSort(alreadySortedByPropertyPaths, (IOrderedQueryable <TEntity>)query);
            }
            else
            {
                query = ApplyDefaultSort(alreadySortedByPropertyPaths, query);
                query = ApplyUniqueSort(alreadySortedByPropertyPaths, (IOrderedQueryable <TEntity>)query);
            }

            return(CreatePaginationResult(query, form, true));
        }
Example #6
0
        /// <summary>
        /// Applies the pagination form to the query.
        /// </summary>
        /// <param name="query">The query that should be paginated.</param>
        /// <param name="form">The pagination form that should be applied to the query.</param>
        /// <returns>A pagination result.</returns>
        public virtual PaginationResult <TEntity> ApplyPagination(IQueryable <TEntity> query, IPageForm form)
        {
            bool isSorted = false;

            var sorting = form.GetSorting(_parameter)?.ToList();

            if (sorting != null && sorting.Count > 0)
            {
                // first order by user specified sorting
                query    = query.OrderBy(_parameter, sorting);
                isSorted = true;

                if (_uniqueSort != null)
                {
                    query = ApplyOrdering(query, _uniqueSort, _uniqueSortDirection, ref isSorted);
                }
                else if (_defaultSort != null)
                {
                    query = ApplyOrdering(query, _defaultSort, _defaultSortDirection, ref isSorted);
                }
            }
            else
            {
                // first order by default sorting
                if (_defaultSort != null)
                {
                    query = ApplyOrdering(query, _defaultSort, _defaultSortDirection, ref isSorted);
                }

                // then order by unique sorting, if present, and not equal to unique sorting
                if (_uniqueSort != null)
                {
                    if (!(ReferenceEquals(_uniqueSort, _defaultSort) && _uniqueSortDirection == _defaultSortDirection))
                    {
                        query = ApplyOrdering(query, _uniqueSort, _uniqueSortDirection, ref isSorted);
                    }
                }
            }

            return(CreatePaginationResult(query, form, true));
        }
        /// <summary>
        /// Applies the pagination form to the query.
        /// </summary>
        /// <param name="query">The query that should be paginated.</param>
        /// <param name="form">The pagination form that should be applied to the query.</param>
        /// <returns>A pagination result.</returns>
        public virtual PaginationResult <TEntity> ApplyPagination(IQueryable <TEntity> query, IPageForm form)
        {
            var sorting = form.GetSorting(_parameter)?.ToList();
            var alreadySortedByPropertyPaths = new List <string>();

            if (sorting != null && sorting.Count > 0)
            {
                // first order by user specified sorting
                query = query.OrderBy(_parameter, sorting);
                alreadySortedByPropertyPaths.AddRange(sorting.Select(x => x.PropertyPath));

                query = ApplyUniqueSort(alreadySortedByPropertyPaths, (IOrderedQueryable <TEntity>)query);
            }
            else
            {
                query = ApplyDefaultSort(alreadySortedByPropertyPaths, query);
                query = ApplyUniqueSort(alreadySortedByPropertyPaths, (IOrderedQueryable <TEntity>)query);
            }

            return(CreatePaginationResult(query, form, true));
        }